LCOV - code coverage report
Current view: top level - source4/smb_server/smb2 - receive.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 293 437 67.0 %
Date: 2023-11-21 12:31:41 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB2 implementation.
       3             :    
       4             :    Copyright (C) Andrew Tridgell        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 "system/time.h"
      23             : #include "libcli/smb2/smb2.h"
      24             : #include "libcli/smb2/smb2_calls.h"
      25             : #include "smb_server/smb_server.h"
      26             : #include "smb_server/smb2/smb2_server.h"
      27             : #include "samba/service_stream.h"
      28             : #include "lib/stream/packet.h"
      29             : #include "ntvfs/ntvfs.h"
      30             : #include "param/param.h"
      31             : #include "auth/auth.h"
      32             : #include "lib/util/idtree.h"
      33             : 
      34             : /* fill in the bufinfo */
      35      412893 : void smb2srv_setup_bufinfo(struct smb2srv_request *req)
      36             : {
      37      412893 :         req->in.bufinfo.mem_ctx    = req;
      38      412893 :         req->in.bufinfo.flags      = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
      39      412893 :         req->in.bufinfo.align_base = req->in.buffer;
      40      412893 :         if (req->in.dynamic) {
      41      267736 :                 req->in.bufinfo.data       = req->in.dynamic;
      42      267736 :                 req->in.bufinfo.data_size  = req->in.body_size - req->in.body_fixed;
      43             :         } else {
      44      145157 :                 req->in.bufinfo.data       = NULL;
      45      145157 :                 req->in.bufinfo.data_size  = 0;
      46             :         }
      47      412893 : }
      48             : 
      49      411679 : static int smb2srv_request_destructor(struct smb2srv_request *req)
      50             : {
      51      411679 :         DLIST_REMOVE(req->smb_conn->requests2.list, req);
      52      411679 :         if (req->pending_id) {
      53       51248 :                 idr_remove(req->smb_conn->requests2.idtree_req, req->pending_id);
      54             :         }
      55      411679 :         return 0;
      56             : }
      57             : 
      58       51248 : static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
      59             : {
      60       51248 :         return -1;
      61             : }
      62             : 
      63      411679 : struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
      64             : {
      65           0 :         struct smb2srv_request *req;
      66             : 
      67      411679 :         req = talloc_zero(smb_conn, struct smb2srv_request);
      68      411679 :         if (!req) return NULL;
      69             : 
      70      411679 :         req->smb_conn = smb_conn;
      71             : 
      72      411679 :         req->chained_session_id = UINT64_MAX;
      73      411679 :         req->chained_tree_id = UINT32_MAX;
      74             : 
      75      411679 :         talloc_set_destructor(req, smb2srv_request_destructor);
      76             : 
      77      411679 :         return req;
      78             : }
      79             : 
      80      464139 : NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
      81             :                              bool body_dynamic_present, uint32_t body_dynamic_size)
      82             : {
      83      464139 :         uint32_t flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
      84      464139 :         uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
      85      464139 :         uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
      86      464139 :         uint16_t credits = SVAL(req->in.hdr, SMB2_HDR_CREDIT);
      87             : 
      88      464139 :         if (credits == 0) {
      89        2145 :                 credits = 1;
      90             :         }
      91             : 
      92      464139 :         flags |= SMB2_HDR_FLAG_REDIRECT;
      93             : 
      94      464139 :         if (req->pending_id) {
      95      102496 :                 flags |= SMB2_HDR_FLAG_ASYNC;
      96      102496 :                 pid = req->pending_id;
      97      102496 :                 tid = 0;
      98      102496 :                 credits = 0;
      99             :         }
     100             : 
     101      464139 :         if (body_dynamic_present) {
     102      319178 :                 if (body_dynamic_size == 0) {
     103      312634 :                         body_dynamic_size = 1;
     104             :                 }
     105             :         } else {
     106      144961 :                 body_dynamic_size = 0;
     107             :         }
     108             : 
     109      464139 :         req->out.size                = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
     110             : 
     111      464139 :         req->out.allocated   = req->out.size + body_dynamic_size;
     112      464139 :         req->out.buffer              = talloc_array(req, uint8_t, 
     113             :                                                req->out.allocated);
     114      464139 :         NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
     115             : 
     116      464139 :         req->out.hdr         = req->out.buffer    + NBT_HDR_SIZE;
     117      464139 :         req->out.body                = req->out.hdr               + SMB2_HDR_BODY;
     118      464139 :         req->out.body_fixed  = body_fixed_size;
     119      464139 :         req->out.body_size   = body_fixed_size;
     120      464139 :         req->out.dynamic     = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
     121             : 
     122      464139 :         SIVAL(req->out.hdr, 0,                               SMB2_MAGIC);
     123      464139 :         SSVAL(req->out.hdr, SMB2_HDR_LENGTH,         SMB2_HDR_BODY);
     124      464139 :         SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE,
     125             :               SVAL(req->in.hdr, SMB2_HDR_CREDIT_CHARGE));
     126      464139 :         SIVAL(req->out.hdr, SMB2_HDR_STATUS,         NT_STATUS_V(req->status));
     127      464139 :         SSVAL(req->out.hdr, SMB2_HDR_OPCODE,         SVAL(req->in.hdr, SMB2_HDR_OPCODE));
     128      464139 :         SSVAL(req->out.hdr, SMB2_HDR_CREDIT,         credits);
     129      464139 :         SIVAL(req->out.hdr, SMB2_HDR_FLAGS,          flags);
     130      464139 :         SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND,   0);
     131      464139 :         SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID,     req->seqnum);
     132      464139 :         SIVAL(req->out.hdr, SMB2_HDR_PID,            pid);
     133      464139 :         SIVAL(req->out.hdr, SMB2_HDR_TID,            tid);
     134      464139 :         SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID,     BVAL(req->in.hdr, SMB2_HDR_SESSION_ID));
     135      464139 :         memcpy(req->out.hdr+SMB2_HDR_SIGNATURE,
     136      464139 :                req->in.hdr+SMB2_HDR_SIGNATURE, 16);
     137             : 
     138             :         /* set the length of the fixed body part and +1 if there's a dynamic part also */
     139      464139 :         SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
     140             : 
     141             :         /* 
     142             :          * if we have a dynamic part, make sure the first byte
     143             :          * which is always be part of the packet is initialized
     144             :          */
     145      464139 :         if (body_dynamic_size) {
     146      319178 :                 req->out.size += 1;
     147      319178 :                 SCVAL(req->out.dynamic, 0, 0);
     148             :         }
     149             : 
     150      464139 :         return NT_STATUS_OK;
     151             : }
     152             : 
     153             : static NTSTATUS smb2srv_reply(struct smb2srv_request *req);
     154             : 
     155           0 : static void smb2srv_chain_reply(struct smb2srv_request *p_req)
     156             : {
     157           0 :         NTSTATUS status;
     158           0 :         struct smbsrv_connection *smb_conn = p_req->smb_conn;
     159           0 :         struct smb2srv_request *req;
     160           0 :         uint32_t chain_offset;
     161           0 :         uint32_t protocol_version;
     162           0 :         uint16_t buffer_code;
     163           0 :         uint32_t dynamic_size;
     164           0 :         uint32_t flags;
     165           0 :         uint32_t last_hdr_offset;
     166             : 
     167           0 :         last_hdr_offset = p_req->in.hdr - p_req->in.buffer;
     168             : 
     169           0 :         chain_offset = p_req->chain_offset;
     170           0 :         p_req->chain_offset = 0;
     171             : 
     172           0 :         if (p_req->in.size < (last_hdr_offset + chain_offset + SMB2_MIN_SIZE_NO_BODY)) {
     173           0 :                 DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X from last hdr 0x%X\n",
     174             :                         chain_offset, last_hdr_offset));
     175           0 :                 smbsrv_terminate_connection(smb_conn, "Invalid SMB2 chained packet");
     176           0 :                 return;
     177             :         }
     178             : 
     179           0 :         protocol_version = IVAL(p_req->in.buffer, last_hdr_offset + chain_offset);
     180           0 :         if (protocol_version != SMB2_MAGIC) {
     181           0 :                 DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
     182             :                          protocol_version));
     183           0 :                 smbsrv_terminate_connection(smb_conn, "NON-SMB2 chained packet");
     184           0 :                 return;
     185             :         }
     186             : 
     187           0 :         req = smb2srv_init_request(smb_conn);
     188           0 :         if (!req) {
     189           0 :                 smbsrv_terminate_connection(smb_conn, "SMB2 chained packet - no memory");
     190           0 :                 return;
     191             :         }
     192             : 
     193           0 :         talloc_steal(req, p_req);
     194             : 
     195           0 :         req->in.buffer               = talloc_steal(req, p_req->in.buffer);
     196           0 :         req->in.size         = p_req->in.size;
     197           0 :         req->request_time    = p_req->request_time;
     198           0 :         req->in.allocated    = req->in.size;
     199             : 
     200           0 :         req->in.hdr          = req->in.buffer+ last_hdr_offset + chain_offset;
     201           0 :         req->in.body         = req->in.hdr        + SMB2_HDR_BODY;
     202           0 :         req->in.body_size    = req->in.size       - (last_hdr_offset+ chain_offset + SMB2_HDR_BODY);
     203           0 :         req->in.dynamic      = NULL;
     204             : 
     205           0 :         req->seqnum          = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
     206             : 
     207           0 :         if (req->in.body_size < 2) {
     208             :                 /* error handling for this is different for negprot to 
     209             :                    other packet types */
     210           0 :                 uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
     211           0 :                 if (opcode == SMB2_OP_NEGPROT) {
     212           0 :                         smbsrv_terminate_connection(smb_conn, "Bad body size in SMB2 negprot");
     213           0 :                         return;
     214             :                 } else {
     215           0 :                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     216           0 :                         return;
     217             :                 }
     218             :         }
     219             : 
     220           0 :         buffer_code             = SVAL(req->in.body, 0);
     221           0 :         req->in.body_fixed   = (buffer_code & ~1);
     222           0 :         dynamic_size            = req->in.body_size - req->in.body_fixed;
     223             : 
     224           0 :         if (dynamic_size != 0 && (buffer_code & 1)) {
     225           0 :                 req->in.dynamic = req->in.body + req->in.body_fixed;
     226           0 :                 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
     227           0 :                         DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n", 
     228             :                                  dynamic_size));
     229           0 :                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     230           0 :                         return;
     231             :                 }
     232             :         }
     233             : 
     234           0 :         smb2srv_setup_bufinfo(req);
     235             : 
     236           0 :         flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
     237           0 :         if (flags & SMB2_HDR_FLAG_CHAINED) {
     238           0 :                 if (p_req->chained_file_handle) {
     239           0 :                         memcpy(req->_chained_file_handle,
     240           0 :                                p_req->_chained_file_handle,
     241             :                                sizeof(req->_chained_file_handle));
     242           0 :                         req->chained_file_handle = req->_chained_file_handle;
     243             :                 }
     244           0 :                 req->chained_session_id = p_req->chained_session_id;
     245           0 :                 req->chained_tree_id = p_req->chained_tree_id;
     246           0 :                 req->chain_status = p_req->chain_status;
     247             :         }
     248             : 
     249             :         /* 
     250             :          * TODO: - make sure the length field is 64
     251             :          *       - make sure it's a request
     252             :          */
     253             : 
     254           0 :         status = smb2srv_reply(req);
     255           0 :         if (!NT_STATUS_IS_OK(status)) {
     256           0 :                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
     257           0 :                 return;
     258             :         }
     259             : }
     260             : 
     261      464139 : void smb2srv_send_reply(struct smb2srv_request *req)
     262             : {
     263           0 :         DATA_BLOB blob;
     264           0 :         NTSTATUS status;
     265             : 
     266      464139 :         if (req->smb_conn->connection->event.fde == NULL) {
     267             :                 /* the socket has been destroyed - no point trying to send a reply! */
     268           0 :                 talloc_free(req);
     269           0 :                 return;
     270             :         }
     271             : 
     272      464139 :         if (req->out.size > NBT_HDR_SIZE) {
     273      464139 :                 _smb_setlen_tcp(req->out.buffer, req->out.size - NBT_HDR_SIZE);
     274             :         }
     275             : 
     276             :         /* if signing is active on the session then sign the packet */
     277      464139 :         if (req->is_signed) {
     278      409735 :                 status = smb2_sign_message(&req->out, 
     279      409735 :                                            req->session->session_info->session_key);
     280      409735 :                 if (!NT_STATUS_IS_OK(status)) {
     281           0 :                         smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     282           0 :                         return;
     283             :                 }               
     284             :         }
     285             : 
     286             : 
     287      464139 :         blob = data_blob_const(req->out.buffer, req->out.size);
     288      464139 :         status = packet_send(req->smb_conn->packet, blob);
     289      464139 :         if (!NT_STATUS_IS_OK(status)) {
     290           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     291           0 :                 return;
     292             :         }
     293      464139 :         if (req->chain_offset) {
     294           0 :                 smb2srv_chain_reply(req);
     295           0 :                 return;
     296             :         }
     297      464139 :         talloc_free(req);
     298             : }
     299             : 
     300       70649 : void smb2srv_send_error(struct smb2srv_request *req, NTSTATUS error)
     301             : {
     302           0 :         NTSTATUS status;
     303             : 
     304       70649 :         if (req->smb_conn->connection->event.fde == NULL) {
     305             :                 /* the socket has been destroyed - no point trying to send an error! */
     306           0 :                 talloc_free(req);
     307           0 :                 return;
     308             :         }
     309             : 
     310       70649 :         status = smb2srv_setup_reply(req, 8, true, 0);
     311       70649 :         if (!NT_STATUS_IS_OK(status)) {
     312           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     313           0 :                 talloc_free(req);
     314           0 :                 return;
     315             :         }
     316             : 
     317       70649 :         SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(error));
     318             : 
     319       70649 :         SSVAL(req->out.body, 0x02, 0);
     320       70649 :         SIVAL(req->out.body, 0x04, 0);
     321             : 
     322       70649 :         req->chain_status = NT_STATUS_INVALID_PARAMETER;
     323             : 
     324       70649 :         smb2srv_send_reply(req);
     325             : }
     326             : 
     327      411626 : static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
     328             : {
     329           0 :         uint16_t opcode;
     330           0 :         uint32_t tid;
     331           0 :         uint64_t uid;
     332           0 :         uint32_t flags;
     333             : 
     334      411626 :         if (SVAL(req->in.hdr, SMB2_HDR_LENGTH) != SMB2_HDR_BODY) {
     335           0 :                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 header length");
     336           0 :                 return NT_STATUS_INVALID_PARAMETER;
     337             :         }
     338      411626 :         opcode                  = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
     339      411626 :         req->chain_offset    = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND);
     340      411626 :         req->seqnum          = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
     341      411626 :         tid                     = IVAL(req->in.hdr, SMB2_HDR_TID);
     342      411626 :         uid                     = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
     343      411626 :         flags                   = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
     344             : 
     345      411626 :         if (opcode != SMB2_OP_CANCEL &&
     346      411624 :             req->smb_conn->highest_smb2_seqnum != 0 &&
     347      409624 :             req->seqnum <= req->smb_conn->highest_smb2_seqnum) {
     348           0 :                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 sequence number");
     349           0 :                 return NT_STATUS_INVALID_PARAMETER;
     350             :         }
     351      411626 :         if (opcode != SMB2_OP_CANCEL) {
     352      411624 :                 req->smb_conn->highest_smb2_seqnum = req->seqnum;
     353             :         }
     354             : 
     355      411626 :         if (flags & SMB2_HDR_FLAG_CHAINED) {
     356           0 :                 uid = req->chained_session_id;
     357           0 :                 tid = req->chained_tree_id;
     358             :         }
     359             : 
     360      411626 :         req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
     361      411626 :         req->tcon    = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
     362             : 
     363      411626 :         req->chained_session_id = uid;
     364      411626 :         req->chained_tree_id = tid;
     365             : 
     366      411626 :         errno = 0;
     367             : 
     368             :         /* supporting signing is mandatory in SMB2, and is per-packet. So we 
     369             :            should check the signature on any incoming packet that is signed, and 
     370             :            should give a signed reply to any signed request */
     371      411626 :         if (flags & SMB2_HDR_FLAG_SIGNED) {
     372           0 :                 NTSTATUS status;
     373             : 
     374      408190 :                 if (!req->session) goto nosession;
     375             : 
     376      408184 :                 req->is_signed = true;
     377      408184 :                 status = smb2_check_signature(&req->in, 
     378      408184 :                                               req->session->session_info->session_key);
     379      408184 :                 if (!NT_STATUS_IS_OK(status)) {
     380           0 :                         smb2srv_send_error(req, status);
     381           0 :                         return NT_STATUS_OK;                    
     382             :                 }
     383        3436 :         } else if (req->session && req->session->smb2_signing.active) {
     384             :                 /* we require signing and this request was not signed */
     385           0 :                 smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
     386           0 :                 return NT_STATUS_OK;                                    
     387             :         }
     388             : 
     389      411620 :         if (!NT_STATUS_IS_OK(req->chain_status)) {
     390           0 :                 smb2srv_send_error(req, req->chain_status);
     391           0 :                 return NT_STATUS_OK;
     392             :         }
     393             : 
     394      411620 :         switch (opcode) {
     395         394 :         case SMB2_OP_NEGPROT:
     396         394 :                 smb2srv_negprot_recv(req);
     397      411607 :                 return NT_STATUS_OK;
     398        2739 :         case SMB2_OP_SESSSETUP:
     399        2739 :                 smb2srv_sesssetup_recv(req);
     400        2739 :                 return NT_STATUS_OK;
     401           5 :         case SMB2_OP_LOGOFF:
     402           6 :                 if (!req->session) goto nosession;
     403           4 :                 smb2srv_logoff_recv(req);
     404           4 :                 return NT_STATUS_OK;
     405        1603 :         case SMB2_OP_TCON:
     406        1603 :                 if (!req->session) goto nosession;
     407        1603 :                 smb2srv_tcon_recv(req);
     408        1603 :                 return NT_STATUS_OK;
     409         451 :         case SMB2_OP_TDIS:
     410         451 :                 if (!req->session) goto nosession;
     411         456 :                 if (!req->tcon)      goto notcon;
     412         445 :                 smb2srv_tdis_recv(req);
     413         445 :                 return NT_STATUS_OK;
     414      209344 :         case SMB2_OP_CREATE:
     415      209344 :                 if (!req->session) goto nosession;
     416      209344 :                 if (!req->tcon)      goto notcon;
     417      209342 :                 smb2srv_create_recv(req);
     418      209342 :                 return NT_STATUS_OK;
     419      142603 :         case SMB2_OP_CLOSE:
     420      142603 :                 if (!req->session) goto nosession;
     421      142603 :                 if (!req->tcon)      goto notcon;
     422      142601 :                 smb2srv_close_recv(req);
     423      142601 :                 return NT_STATUS_OK;
     424           3 :         case SMB2_OP_FLUSH:
     425           3 :                 if (!req->session) goto nosession;
     426           3 :                 if (!req->tcon)      goto notcon;
     427           3 :                 smb2srv_flush_recv(req);
     428           3 :                 return NT_STATUS_OK;
     429        1607 :         case SMB2_OP_READ:
     430        1607 :                 if (!req->session) goto nosession;
     431        1607 :                 if (!req->tcon)      goto notcon;
     432        1607 :                 smb2srv_read_recv(req);
     433        1607 :                 return NT_STATUS_OK;
     434        1813 :         case SMB2_OP_WRITE:
     435        1813 :                 if (!req->session) goto nosession;
     436        1813 :                 if (!req->tcon)      goto notcon;
     437        1813 :                 smb2srv_write_recv(req);
     438        1813 :                 return NT_STATUS_OK;
     439         385 :         case SMB2_OP_LOCK:
     440         385 :                 if (!req->session) goto nosession;
     441         385 :                 if (!req->tcon)      goto notcon;
     442         384 :                 smb2srv_lock_recv(req);
     443         384 :                 return NT_STATUS_OK;
     444       48284 :         case SMB2_OP_IOCTL:
     445       48284 :                 if (!req->session) goto nosession;
     446       48283 :                 if (!req->tcon)      goto notcon;
     447       48283 :                 smb2srv_ioctl_recv(req);
     448       48283 :                 return NT_STATUS_OK;
     449           2 :         case SMB2_OP_CANCEL:
     450           2 :                 smb2srv_cancel_recv(req);
     451           2 :                 return NT_STATUS_OK;
     452           1 :         case SMB2_OP_KEEPALIVE:
     453           1 :                 smb2srv_keepalive_recv(req);
     454           1 :                 return NT_STATUS_OK;
     455         906 :         case SMB2_OP_QUERY_DIRECTORY:
     456         906 :                 if (!req->session) goto nosession;
     457         906 :                 if (!req->tcon)      goto notcon;
     458         906 :                 smb2srv_find_recv(req);
     459         906 :                 return NT_STATUS_OK;
     460           0 :         case SMB2_OP_NOTIFY:
     461           0 :                 if (!req->session) goto nosession;
     462           0 :                 if (!req->tcon)      goto notcon;
     463           0 :                 smb2srv_notify_recv(req);
     464           0 :                 return NT_STATUS_OK;
     465         981 :         case SMB2_OP_GETINFO:
     466         981 :                 if (!req->session) goto nosession;
     467         981 :                 if (!req->tcon)      goto notcon;
     468         981 :                 smb2srv_getinfo_recv(req);
     469         981 :                 return NT_STATUS_OK;
     470         457 :         case SMB2_OP_SETINFO:
     471         457 :                 if (!req->session) goto nosession;
     472         457 :                 if (!req->tcon)      goto notcon;
     473         457 :                 smb2srv_setinfo_recv(req);
     474         457 :                 return NT_STATUS_OK;
     475          42 :         case SMB2_OP_BREAK:
     476          42 :                 if (!req->session) goto nosession;
     477          42 :                 if (!req->tcon)      goto notcon;
     478          42 :                 smb2srv_break_recv(req);
     479          42 :                 return NT_STATUS_OK;
     480             :         }
     481             : 
     482           0 :         DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode));
     483           0 :         smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode");
     484           0 :         return NT_STATUS_OK;
     485             : 
     486           8 : nosession:
     487           8 :         smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED);
     488           8 :         return NT_STATUS_OK;
     489          11 : notcon:
     490          11 :         smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED);
     491          11 :         return NT_STATUS_OK;
     492             : }
     493             : 
     494      411626 : NTSTATUS smbsrv_recv_smb2_request(void *private_data, DATA_BLOB blob)
     495             : {
     496      411626 :         struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection);
     497           0 :         struct smb2srv_request *req;
     498      411626 :         struct timeval cur_time = timeval_current();
     499           0 :         uint32_t protocol_version;
     500           0 :         uint16_t buffer_code;
     501           0 :         uint32_t dynamic_size;
     502           0 :         uint32_t flags;
     503             : 
     504      411626 :         smb_conn->statistics.last_request_time = cur_time;
     505             : 
     506             :         /* see if its a special NBT packet */
     507      411626 :         if (CVAL(blob.data,0) != 0) {
     508           0 :                 DEBUG(2,("Special NBT packet on SMB2 connection\n"));
     509           0 :                 smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection");
     510           0 :                 return NT_STATUS_OK;
     511             :         }
     512             : 
     513      411626 :         if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE_NO_BODY)) {
     514           0 :                 DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length));
     515           0 :                 smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet");
     516           0 :                 return NT_STATUS_OK;
     517             :         }
     518             : 
     519      411626 :         protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
     520      411626 :         if (protocol_version != SMB2_MAGIC) {
     521           0 :                 DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
     522             :                          protocol_version));
     523           0 :                 smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet");
     524           0 :                 return NT_STATUS_OK;
     525             :         }
     526             : 
     527      411626 :         req = smb2srv_init_request(smb_conn);
     528      411626 :         NT_STATUS_HAVE_NO_MEMORY(req);
     529             : 
     530      411626 :         req->in.buffer               = talloc_steal(req, blob.data);
     531      411626 :         req->in.size         = blob.length;
     532      411626 :         req->request_time    = cur_time;
     533      411626 :         req->in.allocated    = req->in.size;
     534             : 
     535      411626 :         req->in.hdr          = req->in.buffer+ NBT_HDR_SIZE;
     536      411626 :         req->in.body         = req->in.hdr        + SMB2_HDR_BODY;
     537      411626 :         req->in.body_size    = req->in.size       - (SMB2_HDR_BODY+NBT_HDR_SIZE);
     538      411626 :         req->in.dynamic      = NULL;
     539             : 
     540      411626 :         req->seqnum          = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
     541             : 
     542      411626 :         if (req->in.body_size < 2) {
     543             :                 /* error handling for this is different for negprot to 
     544             :                    other packet types */
     545           0 :                 uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
     546           0 :                 if (opcode == SMB2_OP_NEGPROT) {
     547           0 :                         smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");                       
     548           0 :                         return NT_STATUS_OK;
     549             :                 } else {
     550           0 :                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     551           0 :                         return NT_STATUS_OK;
     552             :                 }
     553             :         }
     554             : 
     555      411626 :         buffer_code             = SVAL(req->in.body, 0);
     556      411626 :         req->in.body_fixed   = (buffer_code & ~1);
     557      411626 :         dynamic_size            = req->in.body_size - req->in.body_fixed;
     558             : 
     559      411626 :         if (dynamic_size != 0 && (buffer_code & 1)) {
     560      267736 :                 req->in.dynamic = req->in.body + req->in.body_fixed;
     561      267736 :                 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
     562           0 :                         DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n", 
     563             :                                  dynamic_size));
     564           0 :                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
     565           0 :                         return NT_STATUS_OK;
     566             :                 }
     567             :         }
     568             : 
     569      411626 :         smb2srv_setup_bufinfo(req);
     570             : 
     571             :         /* 
     572             :          * TODO: - make sure the length field is 64
     573             :          *       - make sure it's a request
     574             :          */
     575             : 
     576      411626 :         flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
     577             :         /* the first request should never have the related flag set */
     578      411626 :         if (flags & SMB2_HDR_FLAG_CHAINED) {
     579           0 :                 req->chain_status = NT_STATUS_INVALID_PARAMETER;
     580             :         }
     581             : 
     582      411626 :         return smb2srv_reply(req);
     583             : }
     584             : 
     585        1608 : static NTSTATUS smb2srv_init_pending(struct smbsrv_connection *smb_conn)
     586             : {
     587        1608 :         smb_conn->requests2.idtree_req = idr_init(smb_conn);
     588        1608 :         NT_STATUS_HAVE_NO_MEMORY(smb_conn->requests2.idtree_req);
     589        1608 :         smb_conn->requests2.idtree_limit     = 0x00FFFFFF & (UINT32_MAX - 1);
     590        1608 :         smb_conn->requests2.list             = NULL;
     591             : 
     592        1608 :         return NT_STATUS_OK;
     593             : }
     594             : 
     595       51248 : NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
     596             : {
     597           0 :         NTSTATUS status;
     598       51248 :         bool signing_used = false;
     599           0 :         int id;
     600       51248 :         uint16_t credits = SVAL(req->in.hdr, SMB2_HDR_CREDIT);
     601             : 
     602       51248 :         if (credits == 0) {
     603         385 :                 credits = 1;
     604             :         }
     605             : 
     606       51248 :         if (req->pending_id) {
     607           0 :                 return NT_STATUS_INTERNAL_ERROR;
     608             :         }
     609             : 
     610       51248 :         if (req->smb_conn->connection->event.fde == NULL) {
     611             :                 /* the socket has been destroyed - no point trying to send an error! */
     612           0 :                 return NT_STATUS_REMOTE_DISCONNECT;
     613             :         }
     614             : 
     615       51248 :         id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req, 
     616       51248 :                                1, req->smb_conn->requests2.idtree_limit);
     617       51248 :         if (id == -1) {
     618           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     619             :         }
     620             : 
     621       51248 :         DLIST_ADD_END(req->smb_conn->requests2.list, req);
     622       51248 :         req->pending_id = id;
     623             : 
     624       51248 :         talloc_set_destructor(req, smb2srv_request_deny_destructor);
     625             : 
     626       51248 :         status = smb2srv_setup_reply(req, 8, true, 0);
     627       51248 :         if (!NT_STATUS_IS_OK(status)) {
     628           0 :                 return status;
     629             :         }
     630             : 
     631       51248 :         SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(NT_STATUS_PENDING));
     632       51248 :         SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credits);
     633             : 
     634       51248 :         SSVAL(req->out.body, 0x02, 0);
     635       51248 :         SIVAL(req->out.body, 0x04, 0);
     636             : 
     637             :         /* if the real reply will be signed set the signed flags, but don't sign */
     638       51248 :         if (req->is_signed) {
     639       51061 :                 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, IVAL(req->out.hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
     640       51061 :                 signing_used = req->is_signed;
     641       51061 :                 req->is_signed = false;
     642             :         }
     643             : 
     644       51248 :         smb2srv_send_reply(req);
     645             : 
     646       51248 :         req->is_signed = signing_used;
     647             : 
     648       51248 :         talloc_set_destructor(req, smb2srv_request_destructor);
     649       51248 :         return NT_STATUS_OK;
     650             : }
     651             : 
     652           2 : void smb2srv_cancel_recv(struct smb2srv_request *req)
     653             : {
     654           0 :         uint32_t pending_id;
     655           0 :         uint32_t flags;
     656           0 :         void *p;
     657           0 :         struct smb2srv_request *r;
     658             : 
     659           2 :         if (!req->session) goto done;
     660             : 
     661           2 :         flags           = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
     662           2 :         pending_id      = IVAL(req->in.hdr, SMB2_HDR_PID);
     663             : 
     664           2 :         if (!(flags & SMB2_HDR_FLAG_ASYNC)) {
     665             :                 /* TODO: what to do here? */
     666           0 :                 goto done;
     667             :         }
     668             :  
     669           2 :         p = idr_find(req->smb_conn->requests2.idtree_req, pending_id);
     670           2 :         if (!p) goto done;
     671             : 
     672           2 :         r = talloc_get_type(p, struct smb2srv_request);
     673           2 :         if (!r) goto done;
     674             : 
     675           2 :         if (!r->ntvfs) goto done;
     676             : 
     677           2 :         ntvfs_cancel(r->ntvfs);
     678             : 
     679           2 : done:
     680             :         /* we never generate a reply for a SMB2 Cancel */
     681           2 :         talloc_free(req);
     682           2 : }
     683             : 
     684             : /*
     685             :  * init the SMB2 protocol related stuff
     686             :  */
     687        1608 : NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
     688             : {
     689           0 :         NTSTATUS status;
     690             : 
     691             :         /* now initialise a few default values associated with this smb socket */
     692        1608 :         smb_conn->negotiate.max_send = 0xFFFF;
     693             : 
     694             :         /* this is the size that w2k uses, and it appears to be important for
     695             :            good performance */
     696        1608 :         smb_conn->negotiate.max_recv = lpcfg_max_xmit(smb_conn->lp_ctx);
     697             : 
     698        1608 :         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
     699             : 
     700        1608 :         smb_conn->config.nt_status_support = true;
     701             : 
     702        1608 :         status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
     703        1608 :         NT_STATUS_NOT_OK_RETURN(status);
     704             : 
     705        1608 :         status = smb2srv_init_pending(smb_conn);
     706        1608 :         NT_STATUS_NOT_OK_RETURN(status);
     707             : 
     708        1608 :         return NT_STATUS_OK;
     709             :         
     710             : }

Generated by: LCOV version 1.14