Spelling fixes for lib/compression.
[sfrench/samba-autobuild/.git] / source3 / smbd / seal.c
index 7dd6e3d7bbf3a1625a1397a1a71f37db6cd930a7..700d7ea02e2e3d22be0403202fba276de8f996e9 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "smbd/globals.h"
+#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
 
 /******************************************************************************
  Server side encryption.
@@ -33,19 +35,39 @@ struct smb_srv_trans_enc_ctx {
        AUTH_NTLMSSP_STATE *auth_ntlmssp_state; /* Must be kept in sync with pointer in ec->ntlmssp_state. */
 };
 
-static struct smb_srv_trans_enc_ctx *partial_srv_trans_enc_ctx;
-static struct smb_srv_trans_enc_ctx *srv_trans_enc_ctx;
+/******************************************************************************
+ Return global enc context - this must change if we ever do multiple contexts.
+******************************************************************************/
+
+uint16_t srv_enc_ctx(void)
+{
+       return srv_trans_enc_ctx->es->enc_ctx_num;
+}
 
 /******************************************************************************
- Is server encryption on ?
+ Is this an incoming encrypted packet ?
 ******************************************************************************/
 
-BOOL srv_encryption_on(void)
+bool is_encrypted_packet(const uint8_t *inbuf)
 {
-       if (srv_trans_enc_ctx) {
-               return common_encryption_on(srv_trans_enc_ctx->es);
+       NTSTATUS status;
+       uint16_t enc_num;
+
+       /* Ignore non-session messages or non 0xFF'E' messages. */
+       if(CVAL(inbuf,0) || !(inbuf[4] == 0xFF && inbuf[5] == 'E')) {
+               return false;
+       }
+
+       status = get_enc_ctx_num(inbuf, &enc_num);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
        }
-       return False;
+
+       /* Encrypted messages are 0xFF'E'<ctx> */
+       if (srv_trans_enc_ctx && enc_num == srv_enc_ctx()) {
+               return true;
+       }
+       return false;
 }
 
 /******************************************************************************
@@ -106,8 +128,7 @@ static NTSTATUS get_srv_gss_creds(const char *service,
        gss_OID_desc nt_hostbased_service =
        {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
 
-       asprintf(&host_princ_s, "%s@%s", service, name);
-       if (host_princ_s == NULL) {
+       if (asprintf(&host_princ_s, "%s@%s", service, name) == -1) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -284,9 +305,9 @@ void srv_free_enc_buffer(char *buf)
 {
        /* We know this is an smb buffer, and we
         * didn't malloc, only copy, for a keepalive,
-        * so ignore session keepalives. */
+        * so ignore non-session messages. */
 
-       if(CVAL(buf,0) == SMBkeepalive) {
+       if(CVAL(buf,0)) {
                return;
        }
 
@@ -301,8 +322,8 @@ void srv_free_enc_buffer(char *buf)
 
 NTSTATUS srv_decrypt_buffer(char *buf)
 {
-       /* Ignore session keepalives. */
-       if(CVAL(buf,0) == SMBkeepalive) {
+       /* Ignore non-session messages. */
+       if(CVAL(buf,0)) {
                return NT_STATUS_OK;
        }
 
@@ -321,8 +342,8 @@ NTSTATUS srv_encrypt_buffer(char *buf, char **buf_out)
 {
        *buf_out = buf;
 
-       /* Ignore session keepalives. */
-       if(CVAL(buf,0) == SMBkeepalive) {
+       /* Ignore non-session messages. */
+       if(CVAL(buf,0)) {
                return NT_STATUS_OK;
        }
 
@@ -346,8 +367,8 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_d
        OM_uint32 flags = 0;
        gss_buffer_desc in_buf, out_buf;
        struct smb_tran_enc_state_gss *gss_state;
-       DATA_BLOB auth_reply = data_blob(NULL,0);
-       DATA_BLOB response = data_blob(NULL,0);
+       DATA_BLOB auth_reply = data_blob_null;
+       DATA_BLOB response = data_blob_null;
        NTSTATUS status;
 
        if (!partial_srv_trans_enc_ctx) {
@@ -365,6 +386,8 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_d
        out_buf.value = NULL;
        out_buf.length = 0;
 
+       become_root();
+
        ret = gss_accept_sec_context(&min,
                                &gss_state->gss_ctx,
                                gss_state->creds,
@@ -376,6 +399,7 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_d
                                &flags,
                                NULL,           /* Ingore time. */
                                NULL);          /* Ignore delegated creds. */
+       unbecome_root();
 
        status = gss_err_to_ntstatus(ret, min);
        if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
@@ -401,9 +425,14 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_d
        data_blob_free(&auth_reply);
 
        SAFE_FREE(*ppdata);
-       *ppdata = response.data;
+       *ppdata = (unsigned char *)memdup(response.data, response.length);
+       if ((*ppdata) == NULL && response.length > 0) {
+               status = NT_STATUS_NO_MEMORY;
+       }
        *p_data_size = response.length;
 
+       data_blob_free(&response);
+
        return status;
 }
 #endif
@@ -413,11 +442,11 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(unsigned char **ppdata, size_t *p_d
  Until success we do everything on the partial enc ctx.
 ******************************************************************************/
 
-static NTSTATUS srv_enc_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob, BOOL spnego_wrap)
+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);
+       DATA_BLOB chal = data_blob_null;
+       DATA_BLOB response = data_blob_null;
 
        status = make_srv_encryption_context(SMB_TRANS_ENC_NTLM, &partial_srv_trans_enc_ctx);
        if (!NT_STATUS_IS_OK(status)) {
@@ -438,8 +467,13 @@ static NTSTATUS srv_enc_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_si
        }
 
        SAFE_FREE(*ppdata);
-       *ppdata = response.data;
+       *ppdata = (unsigned char *)memdup(response.data, response.length);
+       if ((*ppdata) == NULL && response.length > 0) {
+               status = NT_STATUS_NO_MEMORY;
+       }
        *p_data_size = response.length;
+       data_blob_free(&response);
+
        return status;
 }
 
@@ -456,13 +490,13 @@ static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
                                        size_t *p_param_size)
 {
        NTSTATUS status;
-       DATA_BLOB blob = data_blob(NULL,0);
-       DATA_BLOB secblob = data_blob(NULL, 0);
-       BOOL got_kerberos_mechanism = False;
+       DATA_BLOB blob = data_blob_null;
+       DATA_BLOB secblob = data_blob_null;
+       char *kerb_mech = NULL;
 
        blob = data_blob_const(*ppdata, *p_data_size);
 
-       status = parse_spnego_mechanisms(blob, &secblob, &got_kerberos_mechanism);
+       status = parse_spnego_mechanisms(blob, &secblob, &kerb_mech);
        if (!NT_STATUS_IS_OK(status)) {
                return nt_status_squash(status);
        }
@@ -471,13 +505,18 @@ static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
 
        srv_free_encryption_context(&partial_srv_trans_enc_ctx);
 
+       if (kerb_mech) {
+               SAFE_FREE(kerb_mech);
+
 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
-       if (got_kerberos_mechanism && lp_use_kerberos_keytab() ) {
                status = srv_enc_spnego_gss_negotiate(ppdata, p_data_size, secblob);
-       } else 
+#else
+               /* Currently we don't SPNEGO negotiate
+                * back to NTLMSSP as we do in sessionsetupX. We should... */
+               return NT_STATUS_LOGON_FAILURE;
 #endif
-       {
-               status = srv_enc_ntlm_negotiate(ppdata, p_data_size, secblob, True);
+       } else {
+               status = srv_enc_ntlm_negotiate(ppdata, p_data_size, secblob, true);
        }
 
        data_blob_free(&secblob);
@@ -489,8 +528,7 @@ static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
 
        if (NT_STATUS_IS_OK(status)) {
                /* Return the context we're using for this encryption state. */
-               *pparam = SMB_MALLOC(2);
-               if (!*pparam) {
+               if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
                        return NT_STATUS_NO_MEMORY;
                }
                SSVAL(*pparam,0,partial_srv_trans_enc_ctx->es->enc_ctx_num);
@@ -512,10 +550,10 @@ static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
                                        size_t *p_param_size)
 {
        NTSTATUS status;
-       DATA_BLOB blob = data_blob(NULL,0);
-       DATA_BLOB auth = data_blob(NULL,0);
-       DATA_BLOB auth_reply = data_blob(NULL,0);
-       DATA_BLOB response = data_blob(NULL,0);
+       DATA_BLOB blob = data_blob_null;
+       DATA_BLOB auth = data_blob_null;
+       DATA_BLOB auth_reply = data_blob_null;
+       DATA_BLOB response = data_blob_null;
        struct smb_srv_trans_enc_ctx *ec = partial_srv_trans_enc_ctx;
 
        /* We must have a partial context here. */
@@ -534,13 +572,21 @@ static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
        status = auth_ntlmssp_update(ec->auth_ntlmssp_state, auth, &auth_reply);
        data_blob_free(&auth);
 
-       response = spnego_gen_auth_response(&auth_reply, status, OID_NTLMSSP);
+       /* From RFC4178.
+        *
+        *    supportedMech
+        *
+        *          This field SHALL only be present in the first reply from the
+        *                target.
+        * So set mechOID to NULL here.
+        */
+
+       response = spnego_gen_auth_response(&auth_reply, status, NULL);
        data_blob_free(&auth_reply);
 
        if (NT_STATUS_IS_OK(status)) {
                /* Return the context we're using for this encryption state. */
-               *pparam = SMB_MALLOC(2);
-               if (!*pparam) {
+               if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
                        return NT_STATUS_NO_MEMORY;
                }
                SSVAL(*pparam,0,ec->es->enc_ctx_num);
@@ -548,8 +594,11 @@ static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
        }
 
        SAFE_FREE(*ppdata);
-       *ppdata = response.data;
+       *ppdata = (unsigned char *)memdup(response.data, response.length);
+       if ((*ppdata) == NULL && response.length > 0)
+               return NT_STATUS_NO_MEMORY;
        *p_data_size = response.length;
+       data_blob_free(&response);
        return status;
 }
 
@@ -566,12 +615,12 @@ static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
 {
        NTSTATUS status;
        DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
-       DATA_BLOB response = data_blob(NULL,0);
+       DATA_BLOB response = data_blob_null;
        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);
+               status = srv_enc_ntlm_negotiate(ppdata, p_data_size, blob, false);
                if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
                        srv_free_encryption_context(&partial_srv_trans_enc_ctx);
                        return nt_status_squash(status);
@@ -590,8 +639,7 @@ static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
 
        if (NT_STATUS_IS_OK(status)) {
                /* Return the context we're using for this encryption state. */
-               *pparam = SMB_MALLOC(2);
-               if (!*pparam) {
+               if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
                        return NT_STATUS_NO_MEMORY;
                }
                SSVAL(*pparam,0,ec->es->enc_ctx_num);
@@ -600,8 +648,11 @@ static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
 
        /* Return the raw blob. */
        SAFE_FREE(*ppdata);
-       *ppdata = response.data;
+       *ppdata = (unsigned char *)memdup(response.data, response.length);
+       if ((*ppdata) == NULL && response.length > 0)
+               return NT_STATUS_NO_MEMORY;
        *p_data_size = response.length;
+       data_blob_free(&response);
        return status;
 }
 
@@ -687,9 +738,11 @@ NTSTATUS srv_encryption_start(connection_struct *conn)
 
        /* Steal the partial pointer. Deliberate shallow copy. */
        srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
-       srv_trans_enc_ctx->es->enc_on = True;
+       srv_trans_enc_ctx->es->enc_on = true;
 
        partial_srv_trans_enc_ctx = NULL;
+
+       DEBUG(1,("srv_encryption_start: context negotiated\n"));
        return NT_STATUS_OK;
 }