s4-server: use GUID_to_ndr_blob() in cldap and smb servers
[samba.git] / source4 / smb_server / smb2 / negprot.c
index 78c17aa03e064f9f0b38aaf5faab53ed9327e4d4..260822f2c5f5da2ac988e454cbe814c6cc9ccd4f 100644 (file)
 
 #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"
@@ -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, global_loadparm);
-       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 (lp_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  = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
+                                                  "smb2", "max transaction size", 0x10000);
+       io->out.max_read_size      = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
+                                                  "smb2", "max read size", 0x10000);
+       io->out.max_write_size     = lp_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;
 }
@@ -129,16 +166,22 @@ static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negpro
                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;
@@ -204,26 +263,28 @@ void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
        req->in.body_size = body_fixed_size;
        req->in.dynamic   = NULL;
 
+       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_PAD1,               0);
+       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_UNKNOWN1,           0);
+       SSVAL(req->in.hdr, SMB2_HDR_CREDIT,             0);
        SIVAL(req->in.hdr, SMB2_HDR_FLAGS,              0);
-       SIVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET,       0);
-       SBVAL(req->in.hdr, SMB2_HDR_SEQNUM,             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_UID,                0);
-       memset(req->in.hdr+SMB2_HDR_SIG, 0, 16);
+       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;