LCOV - code coverage report
Current view: top level - source4/smb_server/smb2 - negprot.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 133 192 69.3 %
Date: 2024-02-28 12:06:22 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB2 implementation.
       3             :    
       4             :    Copyright (C) Andrew Bartlett        2001-2005
       5             :    Copyright (C) Stefan Metzmacher      2005
       6             :    
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "auth/credentials/credentials.h"
      23             : #include "auth/auth.h"
      24             : #include "auth/gensec/gensec.h"
      25             : #include "libcli/raw/libcliraw.h"
      26             : #include "libcli/raw/raw_proto.h"
      27             : #include "libcli/smb2/smb2.h"
      28             : #include "libcli/smb2/smb2_calls.h"
      29             : #include "smb_server/smb_server.h"
      30             : #include "smb_server/smb2/smb2_server.h"
      31             : #include "samba/service_stream.h"
      32             : #include "param/param.h"
      33             : 
      34        1614 : static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
      35             : {
      36           0 :         struct gensec_security *gensec_security;
      37        1614 :         DATA_BLOB null_data_blob = data_blob(NULL, 0);
      38           0 :         DATA_BLOB blob;
      39           0 :         NTSTATUS nt_status;
      40           0 :         struct cli_credentials *server_credentials;
      41             : 
      42           0 :         server_credentials =
      43        1614 :                 cli_credentials_init_server(req, req->smb_conn->lp_ctx);
      44        1614 :         if (server_credentials == NULL) {
      45           2 :                 DBG_DEBUG("Failed to obtain server credentials, "
      46             :                           "perhaps a standalone server?\n");
      47             :                 /*
      48             :                  * Create anon server credentials for for the
      49             :                  * spoolss.notify test.
      50             :                  */
      51           2 :                 server_credentials = cli_credentials_init_anon(req);
      52           2 :                 if (server_credentials == NULL) {
      53           0 :                         smbsrv_terminate_connection(req->smb_conn,
      54             :                                 "Failed to init server credentials\n");
      55           0 :                         return NT_STATUS_NO_MEMORY;
      56             :                 }
      57             :         }
      58             : 
      59        1614 :         req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
      60             : 
      61        1614 :         nt_status = samba_server_gensec_start(req,
      62        1614 :                                               req->smb_conn->connection->event.ctx,
      63        1614 :                                               req->smb_conn->connection->msg_ctx,
      64        1614 :                                               req->smb_conn->lp_ctx,
      65             :                                               server_credentials,
      66             :                                               "cifs",
      67             :                                               &gensec_security);
      68        1614 :         if (!NT_STATUS_IS_OK(nt_status)) {
      69           0 :                 DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
      70           0 :                 smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
      71           0 :                 return nt_status;
      72             :         }
      73             : 
      74        1614 :         gensec_set_target_service(gensec_security, "cifs");
      75             : 
      76        1614 :         gensec_set_credentials(gensec_security, server_credentials);
      77             : 
      78        1614 :         nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
      79        1614 :         if (!NT_STATUS_IS_OK(nt_status)) {
      80           0 :                 DEBUG(0, ("Failed to start SPNEGO: %s\n", nt_errstr(nt_status)));
      81           0 :                 smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO\n");
      82           0 :                 return nt_status;
      83             :         }
      84             : 
      85        1614 :         nt_status = gensec_update(gensec_security, req,
      86             :                                   null_data_blob, &blob);
      87        1614 :         if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
      88           0 :                 DEBUG(0, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status)));
      89           0 :                 smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO - no first token\n");
      90           0 :                 return nt_status;
      91             :         }
      92             : 
      93        1614 :         *_blob = blob;
      94        1614 :         return NT_STATUS_OK;
      95             : }
      96             : 
      97        1614 : static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2_negprot *io)
      98             : {
      99           0 :         NTSTATUS status;
     100           0 :         struct timeval current_time;
     101           0 :         struct timeval boot_time;
     102           0 :         uint16_t i;
     103        1614 :         uint16_t dialect = 0;
     104           0 :         enum smb_signing_setting signing_setting;
     105        1614 :         struct loadparm_context *lp_ctx = req->smb_conn->lp_ctx;
     106             : 
     107             :         /* we only do one dialect for now */
     108        1614 :         if (io->in.dialect_count < 1) {
     109           0 :                 return NT_STATUS_NOT_SUPPORTED;
     110             :         }
     111        1614 :         for (i=0; i < io->in.dialect_count; i++) {
     112        1614 :                 dialect = io->in.dialects[i];
     113        1614 :                 if (dialect == SMB2_DIALECT_REVISION_202) {
     114        1614 :                         break;
     115             :                 }
     116             :         }
     117        1614 :         if (dialect != SMB2_DIALECT_REVISION_202) {
     118           0 :                 DEBUG(0,("Got unexpected SMB2 dialect %u\n", dialect));
     119           0 :                 return NT_STATUS_NOT_SUPPORTED;
     120             :         }
     121             : 
     122        1614 :         req->smb_conn->negotiate.protocol = PROTOCOL_SMB2_02;
     123             : 
     124        1614 :         current_time = timeval_current(); /* TODO: handle timezone?! */
     125        1614 :         boot_time = timeval_current(); /* TODO: fix me */
     126             : 
     127        1614 :         ZERO_STRUCT(io->out);
     128             : 
     129        1614 :         signing_setting = lpcfg_server_signing(lp_ctx);
     130        1614 :         if (signing_setting == SMB_SIGNING_DEFAULT) {
     131             :                 /*
     132             :                  * If we are a domain controller, SMB signing is
     133             :                  * really important, as it can prevent a number of
     134             :                  * attacks on communications between us and the
     135             :                  * clients
     136             :                  *
     137             :                  * However, it really sucks (no sendfile, CPU
     138             :                  * overhead) performance-wise when used on a
     139             :                  * file server, so disable it by default
     140             :                  * on non-DCs
     141             :                  */
     142             : 
     143        1584 :                 if (lpcfg_server_role(lp_ctx) >= ROLE_ACTIVE_DIRECTORY_DC) {
     144        1582 :                         signing_setting = SMB_SIGNING_REQUIRED;
     145             :                 } else {
     146           2 :                         signing_setting = SMB_SIGNING_OFF;
     147             :                 }
     148             :         }
     149             : 
     150        1614 :         switch (signing_setting) {
     151           0 :         case SMB_SIGNING_DEFAULT:
     152             :         case SMB_SIGNING_IPC_DEFAULT:
     153           0 :                 smb_panic(__location__);
     154           0 :                 break;
     155           2 :         case SMB_SIGNING_OFF:
     156           2 :                 io->out.security_mode = 0;
     157           2 :                 break;
     158          30 :         case SMB_SIGNING_DESIRED:
     159             :         case SMB_SIGNING_IF_REQUIRED:
     160          30 :                 io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
     161          30 :                 break;
     162        1582 :         case SMB_SIGNING_REQUIRED:
     163        1582 :                 io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
     164             :                 /* force signing on immediately */
     165        1582 :                 req->smb_conn->smb2_signing_required = true;
     166        1582 :                 break;
     167             :         }
     168        1614 :         io->out.dialect_revision   = dialect;
     169        1614 :         io->out.capabilities       = 0;
     170        1614 :         io->out.max_transact_size  = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
     171             :                                                    "smb2", "max transaction size", 0x10000);
     172        1614 :         io->out.max_read_size      = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
     173             :                                                    "smb2", "max read size", 0x10000);
     174        1614 :         io->out.max_write_size     = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
     175             :                                                    "smb2", "max write size", 0x10000);
     176        1614 :         io->out.system_time     = timeval_to_nttime(&current_time);
     177        1614 :         io->out.server_start_time  = timeval_to_nttime(&boot_time);
     178        1614 :         io->out.reserved2          = 0;
     179        1614 :         status = smb2srv_negprot_secblob(req, &io->out.secblob);
     180        1614 :         NT_STATUS_NOT_OK_RETURN(status);
     181             : 
     182        1614 :         return NT_STATUS_OK;
     183             : }
     184             : 
     185        1614 : static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io)
     186             : {
     187           0 :         NTSTATUS status;
     188             : 
     189        1614 :         if (NT_STATUS_IS_ERR(req->status)) {
     190           0 :                 smb2srv_send_error(req, req->status); /* TODO: is this correct? */
     191           0 :                 return;
     192             :         }
     193             : 
     194        1614 :         status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
     195        1614 :         if (!NT_STATUS_IS_OK(status)) {
     196           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     197           0 :                 talloc_free(req);
     198           0 :                 return;
     199             :         }
     200             : 
     201        1614 :         SSVAL(req->out.body, 0x02, io->out.security_mode);
     202        1614 :         SIVAL(req->out.body, 0x04, io->out.dialect_revision);
     203        1614 :         SIVAL(req->out.body, 0x06, io->out.reserved);
     204        1614 :         status = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
     205        1614 :         if (!NT_STATUS_IS_OK(status)) {
     206           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     207           0 :                 talloc_free(req);
     208           0 :                 return;
     209             :         }
     210        1614 :         SIVAL(req->out.body, 0x18, io->out.capabilities);
     211        1614 :         SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
     212        1614 :         SIVAL(req->out.body, 0x20, io->out.max_read_size);
     213        1614 :         SIVAL(req->out.body, 0x24, io->out.max_write_size);
     214        1614 :         push_nttime(req->out.body, 0x28, io->out.system_time);
     215        1614 :         push_nttime(req->out.body, 0x30, io->out.server_start_time);
     216        1614 :         SIVAL(req->out.body, 0x3C, io->out.reserved2);
     217        1614 :         status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
     218        1614 :         if (!NT_STATUS_IS_OK(status)) {
     219           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     220           0 :                 talloc_free(req);
     221           0 :                 return;
     222             :         }
     223             : 
     224        1614 :         smb2srv_send_reply(req);
     225             : }
     226             : 
     227        1614 : void smb2srv_negprot_recv(struct smb2srv_request *req)
     228             : {
     229           0 :         struct smb2_negprot *io;
     230           0 :         int i;
     231             : 
     232        1614 :         if (req->in.body_size < 0x26) {
     233           0 :                 smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
     234           0 :                 return;
     235             :         }
     236             : 
     237        1614 :         io = talloc(req, struct smb2_negprot);
     238        1614 :         if (!io) {
     239           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
     240           0 :                 talloc_free(req);
     241           0 :                 return;
     242             :         }
     243             : 
     244        1614 :         io->in.dialect_count = SVAL(req->in.body, 0x02);
     245        1614 :         io->in.security_mode = SVAL(req->in.body, 0x04);
     246        1614 :         io->in.reserved      = SVAL(req->in.body, 0x06);
     247        1614 :         io->in.capabilities  = IVAL(req->in.body, 0x08);
     248        1614 :         req->status = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
     249        1614 :         if (!NT_STATUS_IS_OK(req->status)) {
     250           0 :                 smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot");
     251           0 :                 talloc_free(req);
     252           0 :                 return;
     253             :         }
     254        1614 :         io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);
     255             : 
     256        1614 :         io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
     257        1614 :         if (io->in.dialects == NULL) {
     258           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
     259           0 :                 talloc_free(req);
     260           0 :                 return;
     261             :         }
     262        4788 :         for (i=0;i<io->in.dialect_count;i++) {
     263        3174 :                 io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
     264             :         }
     265             : 
     266        1614 :         req->status = smb2srv_negprot_backend(req, io);
     267             : 
     268        1614 :         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
     269           0 :                 talloc_free(req);
     270           0 :                 return;
     271             :         }
     272        1614 :         smb2srv_negprot_send(req, io);
     273             : }
     274             : 
     275             : /*
     276             :  * reply to a SMB negprot request with dialect "SMB 2.002"
     277             :  */
     278        1220 : void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
     279             : {
     280           0 :         struct smb2srv_request *req;
     281        1220 :         uint32_t body_fixed_size = 0x26;
     282             : 
     283        1220 :         req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
     284        1220 :         if (!req) goto nomem;
     285        1220 :         req->smb_conn                = smb_req->smb_conn;
     286        1220 :         req->request_time    = smb_req->request_time;
     287        1220 :         talloc_steal(req, smb_req);
     288             : 
     289        1220 :         req->in.size      = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
     290        1220 :         req->in.allocated = req->in.size;
     291        1220 :         req->in.buffer    = talloc_array(req, uint8_t, req->in.allocated);
     292        1220 :         if (!req->in.buffer) goto nomem;
     293        1220 :         req->in.hdr       = req->in.buffer + NBT_HDR_SIZE;
     294        1220 :         req->in.body      = req->in.hdr + SMB2_HDR_BODY;
     295        1220 :         req->in.body_size = body_fixed_size;
     296        1220 :         req->in.dynamic   = NULL;
     297             : 
     298        1220 :         smb2srv_setup_bufinfo(req);
     299             : 
     300        1220 :         SIVAL(req->in.hdr, 0,                                SMB2_MAGIC);
     301        1220 :         SSVAL(req->in.hdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
     302        1220 :         SSVAL(req->in.hdr, SMB2_HDR_EPOCH,           0);
     303        1220 :         SIVAL(req->in.hdr, SMB2_HDR_STATUS,          0);
     304        1220 :         SSVAL(req->in.hdr, SMB2_HDR_OPCODE,          SMB2_OP_NEGPROT);
     305        1220 :         SSVAL(req->in.hdr, SMB2_HDR_CREDIT,          0);
     306        1220 :         SIVAL(req->in.hdr, SMB2_HDR_FLAGS,           0);
     307        1220 :         SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,    0);
     308        1220 :         SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,              0);
     309        1220 :         SIVAL(req->in.hdr, SMB2_HDR_PID,             0);
     310        1220 :         SIVAL(req->in.hdr, SMB2_HDR_TID,             0);
     311        1220 :         SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,              0);
     312        1220 :         memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
     313             : 
     314             :         /* this seems to be a bug, they use 0x24 but the length is 0x26 */
     315        1220 :         SSVAL(req->in.body, 0x00, 0x24);
     316             : 
     317        1220 :         SSVAL(req->in.body, 0x02, 1);
     318        1220 :         memset(req->in.body+0x04, 0, 32);
     319        1220 :         SSVAL(req->in.body, 0x24, SMB2_DIALECT_REVISION_202);
     320             : 
     321        1220 :         smb2srv_negprot_recv(req);
     322        1220 :         return;
     323           0 : nomem:
     324           0 :         smbsrv_terminate_connection(smb_req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
     325           0 :         talloc_free(req);
     326           0 :         return;
     327             : }

Generated by: LCOV version 1.14