r21882: The server part of the code has to use an AUTH_NTLMSSP struct,
authorJeremy Allison <jra@samba.org>
Tue, 20 Mar 2007 01:17:47 +0000 (01:17 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:18:43 +0000 (12:18 -0500)
not just an NTLMSSP - grr. This complicates the re-use of
common client and server code but I think I've got it right.
Not turned on of valgrinded yet, but you can see it start
to take shape !
Jeremy.

source/Makefile.in
source/lib/dummysmbd.c
source/libsmb/smb_seal.c
source/smbd/seal.c [new file with mode: 0644]
source/smbd/server.c
source/smbd/sesssetup.c
source/smbd/trans2.c

index 40351900c87669f94ea9cf599a92f72ae376235c..4d3fb106cd584edf5e91902bf8a7b521f68c6352 100644 (file)
@@ -472,7 +472,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
                smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \
               smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \
               smbd/blocking.o smbd/sec_ctx.o smbd/srvstr.o \
-              smbd/vfs.o smbd/statcache.o \
+              smbd/vfs.o smbd/statcache.o smbd/seal.o \
                smbd/posix_acls.o lib/sysacls.o $(SERVER_MUTEX_OBJ) \
               smbd/process.o smbd/service.o smbd/error.o \
               printing/printfsp.o lib/sysquotas.o lib/sysquotas_linux.o \
index a291a5884d9d546f170cbe0ce975a401e440c971..6017a12928212a73310e6b2ed97dcc3793c1e57b 100644 (file)
@@ -48,3 +48,18 @@ NTSTATUS can_delete_directory(struct connection_struct *conn,
        return NT_STATUS_OK;
 }
 
+NTSTATUS srv_decrypt_buffer(char *buf)
+{
+       return NT_STATUS_OK;
+}
+
+NTSTATUS srv_encrypt_buffer(char *buffer, char **buf_out)
+{
+       *buf_out = buffer;
+       return NT_STATUS_OK;
+}
+
+void srv_free_enc_buffer(char *buf)
+{
+       ;
+}
index 2d1201ae7ed8d5a517422531f4c9ddcd520a2d4e..10b9d8fdcb344115a9ef6b370e696016be0387f8 100644 (file)
@@ -25,7 +25,7 @@
  Is encryption turned on ?
 ******************************************************************************/
 
-static BOOL internal_encryption_on(struct smb_trans_enc_state *es)
+BOOL common_encryption_on(struct smb_trans_enc_state *es)
 {
        return ((es != NULL) && es->enc_on);
 }
@@ -35,7 +35,7 @@ static BOOL internal_encryption_on(struct smb_trans_enc_state *es)
  NTLM decrypt an incoming buffer.
 ******************************************************************************/
 
-static NTSTATUS internal_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
+NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
 {
        NTSTATUS status;
        size_t orig_len = smb_len(buf);
@@ -70,7 +70,7 @@ static NTSTATUS internal_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char
  NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
 ******************************************************************************/
 
-static NTSTATUS internal_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, char **ppbuf_out)
+NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, char **ppbuf_out)
 {
        NTSTATUS status;
        char *buf_out;
@@ -123,7 +123,7 @@ static NTSTATUS internal_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char
 ******************************************************************************/
 
 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
-static NTSTATUS internal_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf)
+NTSTATUS common_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf)
 {
        return NT_STATUS_NOT_SUPPORTED;
 }
@@ -135,7 +135,7 @@ static NTSTATUS internal_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *b
 ******************************************************************************/
 
 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
-static NTSTATUS srv_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **buf_out)
+NTSTATUS common_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **buf_out)
 {
        return NT_STATUS_NOT_SUPPORTED;
 }
@@ -146,19 +146,19 @@ static NTSTATUS srv_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, c
  Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
 ******************************************************************************/
 
-static NTSTATUS internal_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
 {
-       if (!internal_encryption_on(es)) {
+       if (!common_encryption_on(es)) {
                /* Not encrypting. */
                *buf_out = buffer;
                return NT_STATUS_OK;
        }
 
        if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
-               return internal_ntlm_encrypt_buffer(es->ntlmssp_state, buffer, buf_out);
+               return common_ntlm_encrypt_buffer(es->ntlmssp_state, buffer, buf_out);
        } else {
 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
-               return internal_gss_encrypt_buffer(es->context_handle, buffer, buf_out);
+               return common_gss_encrypt_buffer(es->context_handle, buffer, buf_out);
 #else
                return NT_STATUS_NOT_SUPPORTED;
 #endif
@@ -171,17 +171,17 @@ static NTSTATUS internal_encrypt_buffer(struct smb_trans_enc_state *es, char *bu
  New data must be less than or equal to the current length.
 ******************************************************************************/
 
-static NTSTATUS internal_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
 {
-       if (!internal_encryption_on(es)) {
+       if (!common_encryption_on(es)) {
                /* Not decrypting. */
                return NT_STATUS_OK;
        }
        if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
-               return internal_ntlm_decrypt_buffer(es->ntlmssp_state, buf);
+               return common_ntlm_decrypt_buffer(es->ntlmssp_state, buf);
        } else {
 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
-               return internal_gss_decrypt_buffer(es->context_handle, buf);
+               return common_gss_decrypt_buffer(es->context_handle, buf);
 #else
                return NT_STATUS_NOT_SUPPORTED;
 #endif
@@ -192,7 +192,7 @@ static NTSTATUS internal_decrypt_buffer(struct smb_trans_enc_state *es, char *bu
  Shutdown an encryption state.
 ******************************************************************************/
 
-static void internal_free_encryption_context(struct smb_trans_enc_state **pp_es)
+void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
 {
        struct smb_trans_enc_state *es = *pp_es;
 
@@ -201,7 +201,9 @@ static void internal_free_encryption_context(struct smb_trans_enc_state **pp_es)
        }
 
        if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
-               ntlmssp_end(&es->ntlmssp_state);
+               if (es->ntlmssp_state) {
+                       ntlmssp_end(&es->ntlmssp_state);
+               }
        }
 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
        if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
@@ -216,9 +218,9 @@ static void internal_free_encryption_context(struct smb_trans_enc_state **pp_es)
  Free an encryption-allocated buffer.
 ******************************************************************************/
 
-static void internal_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
 {
-       if (!internal_encryption_on(es)) {
+       if (!common_encryption_on(es)) {
                return;
        }
 
@@ -242,7 +244,7 @@ static void internal_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
 
 BOOL cli_encryption_on(struct cli_state *cli)
 {
-       return internal_encryption_on(cli->trans_enc_state);
+       return common_encryption_on(cli->trans_enc_state);
 }
 
 /******************************************************************************
@@ -251,7 +253,7 @@ BOOL cli_encryption_on(struct cli_state *cli)
 
 void cli_free_encryption_context(struct cli_state *cli)
 {
-       return internal_free_encryption_context(&cli->trans_enc_state);
+       return common_free_encryption_state(&cli->trans_enc_state);
 }
 
 /******************************************************************************
@@ -260,7 +262,7 @@ void cli_free_encryption_context(struct cli_state *cli)
 
 void cli_free_enc_buffer(struct cli_state *cli, char *buf)
 {
-       return internal_free_enc_buffer(cli->trans_enc_state, buf);
+       return common_free_enc_buffer(cli->trans_enc_state, buf);
 }
 
 /******************************************************************************
@@ -269,7 +271,7 @@ void cli_free_enc_buffer(struct cli_state *cli, char *buf)
 
 NTSTATUS cli_decrypt_message(struct cli_state *cli)
 {
-       return internal_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
+       return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
 }
 
 /******************************************************************************
@@ -278,61 +280,5 @@ NTSTATUS cli_decrypt_message(struct cli_state *cli)
 
 NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
 {
-       return internal_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);
-}
-
-/******************************************************************************
- Server side encryption.
-******************************************************************************/
-
-/******************************************************************************
- Global server state.
-******************************************************************************/
-
-static struct smb_trans_enc_state *partial_srv_trans_enc_state;
-static struct smb_trans_enc_state *srv_trans_enc_state;
-
-/******************************************************************************
- Is server encryption on ?
-******************************************************************************/
-
-BOOL srv_encryption_on(void)
-{
-       return internal_encryption_on(srv_trans_enc_state);
-}
-
-/******************************************************************************
- Shutdown a server encryption state.
-******************************************************************************/
-
-void srv_free_encryption_context(void)
-{
-       return internal_free_encryption_context(&srv_trans_enc_state);
-}
-
-/******************************************************************************
- Free an encryption-allocated buffer.
-******************************************************************************/
-
-void srv_free_enc_buffer(char *buf)
-{
-       return internal_free_enc_buffer(srv_trans_enc_state, buf);
-}
-
-/******************************************************************************
- Decrypt an incoming buffer.
-******************************************************************************/
-
-NTSTATUS srv_decrypt_buffer(char *buf)
-{
-       return internal_decrypt_buffer(srv_trans_enc_state, buf);
-}
-
-/******************************************************************************
- Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
-******************************************************************************/
-
-NTSTATUS srv_encrypt_buffer(char *buffer, char **buf_out)
-{
-       return internal_encrypt_buffer(srv_trans_enc_state, buffer, buf_out);
+       return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);
 }
diff --git a/source/smbd/seal.c b/source/smbd/seal.c
new file mode 100644 (file)
index 0000000..2dd4fc8
--- /dev/null
@@ -0,0 +1,257 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB Transport encryption (sealing) code - server code.
+   Copyright (C) Jeremy Allison 2007.
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+
+/******************************************************************************
+ Server side encryption.
+******************************************************************************/
+
+/******************************************************************************
+ Global server state.
+******************************************************************************/
+
+struct smb_srv_trans_enc_ctx {
+       struct smb_trans_enc_state *es;
+       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;
+
+/******************************************************************************
+ Is server encryption on ?
+******************************************************************************/
+
+BOOL srv_encryption_on(void)
+{
+       if (srv_trans_enc_ctx) {
+               return common_encryption_on(srv_trans_enc_ctx->es);
+       }
+       return False;
+}
+
+/******************************************************************************
+ Shutdown a server encryption state.
+******************************************************************************/
+
+static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec)
+{
+       struct smb_srv_trans_enc_ctx *ec = *pp_ec;
+
+       if (!ec) {
+               return;
+       }
+
+       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;
+               }
+               common_free_encryption_state(&ec->es);
+       }
+
+       SAFE_FREE(ec);
+       *pp_ec = NULL;
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void srv_free_enc_buffer(char *buf)
+{
+       if (srv_trans_enc_ctx) {
+               return common_free_enc_buffer(srv_trans_enc_ctx->es, buf);
+       }
+}
+
+/******************************************************************************
+ Decrypt an incoming buffer.
+******************************************************************************/
+
+NTSTATUS srv_decrypt_buffer(char *buf)
+{
+       if (srv_trans_enc_ctx) {
+               return common_decrypt_buffer(srv_trans_enc_ctx->es, buf);
+       }
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS srv_encrypt_buffer(char *buffer, char **buf_out)
+{
+       if (srv_trans_enc_ctx) {
+               return common_encrypt_buffer(srv_trans_enc_ctx->es, buffer, buf_out);
+       }
+       /* Not encrypting. */
+       *buf_out = buffer;
+       return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Do the gss encryption negotiation. Parameters are in/out.
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+#if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
+static NTSTATUS srv_enc_spnego_gss_negotiate(char **ppdata, size_t *p_data_size, DATA_BLOB *psecblob)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+#endif
+
+/******************************************************************************
+ Do the SPNEGO encryption negotiation. Parameters are in/out.
+ Covers the NTLM case. Based off code in smbd/sesssionsetup.c
+ Until success we do everything on the partial enc ctx.
+******************************************************************************/
+
+static NTSTATUS srv_enc_spnego_negotiate(unsigned char **ppdata, size_t *p_data_size)
+{
+       NTSTATUS status;
+       DATA_BLOB blob = data_blob(NULL,0);
+       DATA_BLOB secblob = data_blob(NULL, 0);
+       DATA_BLOB chal = data_blob(NULL, 0);
+       DATA_BLOB response = data_blob(NULL, 0);
+       BOOL got_kerberos_mechanism = False;
+       struct smb_srv_trans_enc_ctx *ec = NULL;
+
+       blob = data_blob_const(*ppdata, *p_data_size);
+
+       status = parse_spnego_mechanisms(blob, &secblob, &got_kerberos_mechanism);
+       if (!NT_STATUS_IS_OK(status)) {
+               return nt_status_squash(status);
+       }
+
+       /* We should have no partial context at this point. */
+
+       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);
+               if (!NT_STATUS_IS_OK(status)) {
+                       data_blob_free(&secblob);
+                       srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+               }
+               return status;
+       }
+#endif
+
+       /* Deal with an NTLM enc. setup. */
+       ec = partial_srv_trans_enc_ctx;
+
+       status = auth_ntlmssp_start(&ec->auth_ntlmssp_state);
+       if (!NT_STATUS_IS_OK(status)) {
+               srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+               return nt_status_squash(status);
+       }
+
+       status = auth_ntlmssp_update(ec->auth_ntlmssp_state, secblob, &chal);
+       data_blob_free(&secblob);
+
+       /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
+        * for success ... */
+
+       response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP);
+       data_blob_free(&chal);
+
+       SAFE_FREE(*ppdata);
+       *ppdata = response.data;
+       *p_data_size = response.length;
+
+       return status;
+}
+
+/******************************************************************************
+ Complete a SPNEGO encryption negotiation. Parameters are in/out.
+******************************************************************************/
+
+static NTSTATUS srv_enc_spnego_auth(unsigned char **ppdata, size_t *p_data_size)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
+/******************************************************************************
+ Do the SPNEGO encryption negotiation. Parameters are in/out.
+******************************************************************************/
+
+NTSTATUS srv_request_encryption_setup(unsigned char **ppdata, size_t *p_data_size)
+{
+       unsigned char *pdata = *ppdata;
+
+       if (*p_data_size < 1) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (pdata[0] == ASN1_APPLICATION(0)) {
+               /* 
+                * Until success we do everything on the partial
+                * enc state.
+                */
+               /* its a negTokenTarg packet */
+               return srv_enc_spnego_negotiate(ppdata, p_data_size);
+       }
+
+       if (pdata[0] == ASN1_CONTEXT(1)) {
+               /* Its a auth packet */
+               return srv_enc_spnego_auth(ppdata, p_data_size);
+       }
+
+       return NT_STATUS_INVALID_PARAMETER;
+}
+
+/******************************************************************************
+ Negotiation was successful - turn on server-side encryption.
+******************************************************************************/
+
+void srv_encryption_start(void)
+{
+       srv_free_encryption_context(&srv_trans_enc_ctx);
+       /* Steal the partial pointer. Deliberate shallow copy. */
+       srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
+       srv_trans_enc_ctx->es->enc_on = True;
+
+       partial_srv_trans_enc_ctx = NULL;
+}
+
+/******************************************************************************
+ Shutdown all server contexts.
+******************************************************************************/
+
+void server_encryption_shutdown(void)
+{
+       srv_free_encryption_context(&partial_srv_trans_enc_ctx);
+       srv_free_encryption_context(&srv_trans_enc_ctx);
+}
index 3f4313ce7f8505662783a2e92b123d46148a4c14..348d3354d7056b66cb72e12a101e70c50657a4d8 100644 (file)
@@ -743,6 +743,8 @@ static void exit_server_common(enum server_exit_reason how,
        locking_end();
        printing_end();
 
+       server_encryption_shutdown();
+
        if (how != SERVER_EXIT_NORMAL) {
                int oldlevel = DEBUGLEVEL;
                char *last_inbuf = get_InBuffer();
index ff1b2821cca307711ff7dda25c46333546b7354e..91f4a9e12f5f7df6223f8f4c40daf56a0e611aa0 100644 (file)
@@ -634,7 +634,7 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
  Is this a krb5 mechanism ?
 ****************************************************************************/
 
-static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
+NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
 {
        char *OIDs[ASN1_MAX_OIDS];
        int i;
index deb5db1bafea8a0f554f98a83d89ca6849ef0d06..25fd6621e9d6433b3ef2c9d77da74d34e35c7a5e 100644 (file)
@@ -2758,6 +2758,33 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                                }
                                break;
                        }
+               case SMB_REQUEST_TRANSPORT_ENCRYPTION:
+                       {
+                               NTSTATUS status;
+                               size_t data_len = total_data;
+
+                               if (!lp_unix_extensions()) {
+                                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                               }
+
+                               DEBUG( 4,("call_trans2setfsinfo: request transport encrption.\n"));
+
+                               status = srv_request_encryption_setup((unsigned char **)&pdata, &data_len);
+
+                               if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+                                       error_packet_set(outbuf, 0, 0, status, __LINE__,__FILE__);
+                               } else if (!NT_STATUS_IS_OK(status)) {
+                                       return ERROR_NT(status);
+                               }
+
+                               send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len, max_data_bytes);
+
+                               if (NT_STATUS_IS_OK(status)) {
+                                       /* Server-side transport encryption is now *on*. */
+                                       srv_encryption_start();
+                               }
+                               return -1;
+                       }
                case SMB_FS_QUOTA_INFORMATION:
                        {
                                files_struct *fsp = NULL;