s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[kai/samba-autobuild/.git] / source4 / smb_server / smb2 / negprot.c
index fe65917275a6624c820d3ddf97f440b0d9577f57..da60676322a21ae84fab131d6c34918ae61344d4 100644 (file)
@@ -6,7 +6,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 "auth/credentials/credentials.h"
+#include "auth/auth.h"
 #include "auth/gensec/gensec.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
 #include "smb_server/smb_server.h"
-#include "smb_server/service_smb_proto.h"
 #include "smb_server/smb2/smb2_server.h"
 #include "smbd/service_stream.h"
+#include "param/param.h"
 
 static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
 {
@@ -37,24 +39,14 @@ static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *
        NTSTATUS nt_status;
        struct cli_credentials *server_credentials;
 
-       nt_status = gensec_server_start(req,
-                                       req->smb_conn->connection->event.ctx,
-                                       req->smb_conn->connection->msg_ctx,
-                                       &gensec_security);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
-               smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
-               return nt_status;
-       }
-
        server_credentials = cli_credentials_init(req);
        if (!server_credentials) {
                smbsrv_terminate_connection(req->smb_conn, "Failed to init server credentials\n");
                return NT_STATUS_NO_MEMORY;
        }
 
-       cli_credentials_set_conf(server_credentials);
-       nt_status = cli_credentials_set_machine_account(server_credentials);
+       cli_credentials_set_conf(server_credentials, req->smb_conn->lp_ctx);
+       nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
                talloc_free(server_credentials);
@@ -63,6 +55,19 @@ static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *
 
        req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
 
+       nt_status = samba_server_gensec_start(req,
+                                             req->smb_conn->connection->event.ctx,
+                                             req->smb_conn->connection->msg_ctx,
+                                             req->smb_conn->lp_ctx,
+                                             server_credentials,
+                                             "cifs",
+                                             &gensec_security);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
+               smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
+               return nt_status;
+       }
+
        gensec_set_target_service(gensec_security, "cifs");
 
        gensec_set_credentials(gensec_security, server_credentials);
@@ -90,25 +95,57 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
        NTSTATUS status;
        struct timeval current_time;
        struct timeval boot_time;
+       uint16_t i;
+       uint16_t dialect = 0;
+
+       /* we only do one dialect for now */
+       if (io->in.dialect_count < 1) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       for (i=0; i < io->in.dialect_count; i++) {
+               dialect = io->in.dialects[i];
+               if (dialect == SMB2_DIALECT_REVISION_202) {
+                       break;
+               }
+       }
+       if (dialect != SMB2_DIALECT_REVISION_202) {
+               DEBUG(0,("Got unexpected SMB2 dialect %u\n", dialect));
+               return NT_STATUS_NOT_SUPPORTED;
+       }
 
        req->smb_conn->negotiate.protocol = PROTOCOL_SMB2;
 
        current_time = timeval_current(); /* TODO: handle timezone?! */
        boot_time = timeval_current(); /* TODO: fix me */
 
-       io->out._pad            = 0;
-       io->out.unknown2        = 0x06;
-       ZERO_STRUCT(io->out.sessid);
-       io->out.unknown3        = 0x0d;
-       io->out.unknown4        = 0x00;
-       io->out.unknown5        = 0x01;
-       io->out.unknown6        = 0x01;
-       io->out.unknown7        = 0x01;
-       io->out.current_time    = timeval_to_nttime(&current_time);
-       io->out.boot_time       = timeval_to_nttime(&boot_time);
+       ZERO_STRUCT(io->out);
+       switch (lpcfg_server_signing(req->smb_conn->lp_ctx)) {
+       case SMB_SIGNING_OFF:
+               io->out.security_mode = 0;
+               break;
+       case SMB_SIGNING_SUPPORTED:
+       case SMB_SIGNING_AUTO:
+               io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+               break;
+       case SMB_SIGNING_REQUIRED:
+               io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
+               /* force signing on immediately */
+               req->smb_conn->smb2_signing_required = true;
+               break;
+       }
+       io->out.dialect_revision   = dialect;
+       io->out.capabilities       = 0;
+       io->out.max_transact_size  = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
+                                                  "smb2", "max transaction size", 0x10000);
+       io->out.max_read_size      = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
+                                                  "smb2", "max read size", 0x10000);
+       io->out.max_write_size     = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
+                                                  "smb2", "max write size", 0x10000);
+       io->out.system_time        = timeval_to_nttime(&current_time);
+       io->out.server_start_time  = timeval_to_nttime(&boot_time);
+       io->out.reserved2          = 0;
        status = smb2srv_negprot_secblob(req, &io->out.secblob);
        NT_STATUS_NOT_OK_RETURN(status);
-       io->out.unknown9        = 0x204d4c20;
 
        return NT_STATUS_OK;
 }
@@ -122,23 +159,29 @@ static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negpro
                return;
        }
 
-       status = smb2srv_setup_reply(req, 0x40, True, io->out.secblob.length);
+       status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
        if (!NT_STATUS_IS_OK(status)) {
                smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
                talloc_free(req);
                return;
        }
 
-       SSVAL(req->out.body, 0x02, io->out._pad);
-       SIVAL(req->out.body, 0x04, io->out.unknown2);
-       memcpy(req->out.body+0x08, io->out.sessid, 16);
-       SIVAL(req->out.body, 0x18, io->out.unknown3);
-       SSVAL(req->out.body, 0x1C, io->out.unknown4);
-       SIVAL(req->out.body, 0x1E, io->out.unknown5);
-       SIVAL(req->out.body, 0x22, io->out.unknown6);
-       SSVAL(req->out.body, 0x26, io->out.unknown7);
-       push_nttime(req->out.body, 0x28, io->out.current_time);
-       push_nttime(req->out.body, 0x30, io->out.boot_time);
+       SSVAL(req->out.body, 0x02, io->out.security_mode);
+       SIVAL(req->out.body, 0x04, io->out.dialect_revision);
+       SIVAL(req->out.body, 0x06, io->out.reserved);
+       status = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
+       if (!NT_STATUS_IS_OK(status)) {
+               smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+               talloc_free(req);
+               return;
+       }
+       SIVAL(req->out.body, 0x18, io->out.capabilities);
+       SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
+       SIVAL(req->out.body, 0x20, io->out.max_read_size);
+       SIVAL(req->out.body, 0x24, io->out.max_write_size);
+       push_nttime(req->out.body, 0x28, io->out.system_time);
+       push_nttime(req->out.body, 0x30, io->out.server_start_time);
+       SIVAL(req->out.body, 0x3C, io->out.reserved2);
        status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
        if (!NT_STATUS_IS_OK(status)) {
                smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
@@ -146,17 +189,16 @@ static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negpro
                return;
        }
 
-       SIVAL(req->out.body, 0x3C, io->out.unknown9);
-
        smb2srv_send_reply(req);
 }
 
 void smb2srv_negprot_recv(struct smb2srv_request *req)
 {
        struct smb2_negprot *io;
+       int i;
 
        if (req->in.body_size < 0x26) {
-               smb2srv_send_error(req,  NT_STATUS_FOOBAR);
+               smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
                return;
        }
 
@@ -167,9 +209,27 @@ void smb2srv_negprot_recv(struct smb2srv_request *req)
                return;
        }
 
-       io->in.unknown1 = SVAL(req->in.body, 0x02);
-       memcpy(io->in.unknown2, req->in.body + 0x04, 0x20);
-       io->in.unknown3 = SVAL(req->in.body, 0x24);
+       io->in.dialect_count = SVAL(req->in.body, 0x02);
+       io->in.security_mode = SVAL(req->in.body, 0x04);
+       io->in.reserved      = SVAL(req->in.body, 0x06);
+       io->in.capabilities  = IVAL(req->in.body, 0x08);
+       req->status = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
+       if (!NT_STATUS_IS_OK(req->status)) {
+               smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot");
+               talloc_free(req);
+               return;
+       }
+       io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);
+
+       io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
+       if (io->in.dialects == NULL) {
+               smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
+               talloc_free(req);
+               return;
+       }
+       for (i=0;i<io->in.dialect_count;i++) {
+               io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
+       }
 
        req->status = smb2srv_negprot_backend(req, io);
 
@@ -181,14 +241,13 @@ void smb2srv_negprot_recv(struct smb2srv_request *req)
 }
 
 /*
- * reply to a SMB negprot request with dialect "SMB 2.001"
+ * reply to a SMB negprot request with dialect "SMB 2.002"
  */
 void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
 {
        struct smb2srv_request *req;
        uint32_t body_fixed_size = 0x26;
 
-       /* create a fake SMB2 negprot request */
        req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
        if (!req) goto nomem;
        req->smb_conn           = smb_req->smb_conn;
@@ -197,33 +256,35 @@ void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
 
        req->in.size      = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
        req->in.allocated = req->in.size;
-       req->in.buffer    = talloc_size(req, req->in.allocated);
+       req->in.buffer    = talloc_array(req, uint8_t, req->in.allocated);
        if (!req->in.buffer) goto nomem;
        req->in.hdr       = req->in.buffer + NBT_HDR_SIZE;
        req->in.body      = req->in.hdr + SMB2_HDR_BODY;
        req->in.body_size = body_fixed_size;
        req->in.dynamic   = NULL;
 
-       SIVAL(req->in.hdr, 0,                SMB2_MAGIC);
-       SSVAL(req->in.hdr, SMB2_HDR_LENGTH,  SMB2_HDR_BODY);
-       SSVAL(req->in.hdr, SMB2_HDR_PAD1,    0);
-       SIVAL(req->in.hdr, SMB2_HDR_STATUS,  0);
-       SSVAL(req->in.hdr, SMB2_HDR_OPCODE,  SMB2_OP_NEGPROT);
-       SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1,0);
-       SIVAL(req->in.hdr, SMB2_HDR_FLAGS,   0);
-       SIVAL(req->in.hdr, SMB2_HDR_UNKNOWN2,0);
-       SBVAL(req->in.hdr, SMB2_HDR_SEQNUM,  0);
-       SIVAL(req->in.hdr, SMB2_HDR_PID,     0);
-       SIVAL(req->in.hdr, SMB2_HDR_TID,     0);
-       SBVAL(req->in.hdr, SMB2_HDR_UID,     0);
-       memset(req->in.hdr+SMB2_HDR_SIG, 0, 16);
+       smb2srv_setup_bufinfo(req);
+
+       SIVAL(req->in.hdr, 0,                           SMB2_MAGIC);
+       SSVAL(req->in.hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
+       SSVAL(req->in.hdr, SMB2_HDR_EPOCH,              0);
+       SIVAL(req->in.hdr, SMB2_HDR_STATUS,             0);
+       SSVAL(req->in.hdr, SMB2_HDR_OPCODE,             SMB2_OP_NEGPROT);
+       SSVAL(req->in.hdr, SMB2_HDR_CREDIT,             0);
+       SIVAL(req->in.hdr, SMB2_HDR_FLAGS,              0);
+       SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,       0);
+       SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,         0);
+       SIVAL(req->in.hdr, SMB2_HDR_PID,                0);
+       SIVAL(req->in.hdr, SMB2_HDR_TID,                0);
+       SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,         0);
+       memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
 
        /* this seems to be a bug, they use 0x24 but the length is 0x26 */
        SSVAL(req->in.body, 0x00, 0x24);
 
        SSVAL(req->in.body, 0x02, 1);
        memset(req->in.body+0x04, 0, 32);
-       SSVAL(req->in.body, 0x24, 0);
+       SSVAL(req->in.body, 0x24, SMB2_DIALECT_REVISION_202);
 
        smb2srv_negprot_recv(req);
        return;