LCOV - code coverage report
Current view: top level - libcli/smb - smb2cli_session.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 119 142 83.8 %
Date: 2021-09-23 10:06:22 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    smb2 lib
       4             :    Copyright (C) Volker Lendecke 2011
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/network.h"
      22             : #include "../lib/util/tevent_ntstatus.h"
      23             : #include "../libcli/smb/smb_common.h"
      24             : #include "../libcli/smb/smbXcli_base.h"
      25             : 
      26             : struct smb2cli_session_setup_state {
      27             :         struct smbXcli_session *session;
      28             :         uint8_t fixed[24];
      29             :         uint8_t dyn_pad[1];
      30             :         struct iovec *recv_iov;
      31             :         DATA_BLOB out_security_buffer;
      32             :         NTSTATUS status;
      33             : };
      34             : 
      35             : static void smb2cli_session_setup_done(struct tevent_req *subreq);
      36             : 
      37       43046 : struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
      38             :                                 struct tevent_context *ev,
      39             :                                 struct smbXcli_conn *conn,
      40             :                                 uint32_t timeout_msec,
      41             :                                 struct smbXcli_session *session,
      42             :                                 uint8_t in_flags,
      43             :                                 uint32_t in_capabilities,
      44             :                                 uint32_t in_channel,
      45             :                                 uint64_t in_previous_session_id,
      46             :                                 const DATA_BLOB *in_security_buffer)
      47             : {
      48             :         struct tevent_req *req, *subreq;
      49             :         struct smb2cli_session_setup_state *state;
      50             :         uint8_t *buf;
      51             :         uint8_t *dyn;
      52             :         size_t dyn_len;
      53             :         uint8_t security_mode;
      54       43046 :         uint16_t security_buffer_offset = 0;
      55       43046 :         uint16_t security_buffer_length = 0;
      56             : 
      57       43046 :         req = tevent_req_create(mem_ctx, &state,
      58             :                                 struct smb2cli_session_setup_state);
      59       43046 :         if (req == NULL) {
      60           0 :                 return NULL;
      61             :         }
      62             : 
      63       43046 :         if (session == NULL) {
      64           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
      65           0 :                 return tevent_req_post(req, ev);
      66             :         }
      67       43046 :         state->session = session;
      68       43046 :         security_mode = smb2cli_session_security_mode(session);
      69             : 
      70       43046 :         if (in_security_buffer) {
      71       43046 :                 if (in_security_buffer->length > UINT16_MAX) {
      72           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
      73           0 :                         return tevent_req_post(req, ev);
      74             :                 }
      75       43046 :                 security_buffer_offset = SMB2_HDR_BODY + 24;
      76       43046 :                 security_buffer_length = in_security_buffer->length;
      77             :         }
      78             : 
      79       43046 :         buf = state->fixed;
      80             : 
      81       43046 :         SSVAL(buf,  0, 25);
      82       43046 :         SCVAL(buf,  2, in_flags);
      83       43046 :         SCVAL(buf,  3, security_mode);
      84       43046 :         SIVAL(buf,  4, in_capabilities);
      85       43046 :         SIVAL(buf,  8, in_channel);
      86       43046 :         SSVAL(buf, 12, security_buffer_offset);
      87       43046 :         SSVAL(buf, 14, security_buffer_length);
      88       43046 :         SBVAL(buf, 16, in_previous_session_id);
      89             : 
      90       43046 :         if (security_buffer_length > 0) {
      91       43046 :                 dyn = in_security_buffer->data;
      92       43046 :                 dyn_len = in_security_buffer->length;
      93             :         } else {
      94           0 :                 dyn = state->dyn_pad;;
      95           0 :                 dyn_len = sizeof(state->dyn_pad);
      96             :         }
      97             : 
      98       80819 :         subreq = smb2cli_req_send(state, ev,
      99             :                                   conn, SMB2_OP_SESSSETUP,
     100             :                                   0, 0, /* flags */
     101             :                                   timeout_msec,
     102             :                                   NULL, /* tcon */
     103             :                                   session,
     104       42654 :                                   state->fixed, sizeof(state->fixed),
     105             :                                   dyn, dyn_len,
     106             :                                   UINT16_MAX); /* max_dyn_len */
     107       43046 :         if (tevent_req_nomem(subreq, req)) {
     108           0 :                 return tevent_req_post(req, ev);
     109             :         }
     110       43046 :         tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
     111       43046 :         return req;
     112             : }
     113             : 
     114       43046 : static void smb2cli_session_setup_done(struct tevent_req *subreq)
     115             : {
     116       38165 :         struct tevent_req *req =
     117       43046 :                 tevent_req_callback_data(subreq,
     118             :                 struct tevent_req);
     119       38165 :         struct smb2cli_session_setup_state *state =
     120       43046 :                 tevent_req_data(req,
     121             :                 struct smb2cli_session_setup_state);
     122             :         NTSTATUS status;
     123             :         NTSTATUS preauth_status;
     124             :         uint64_t current_session_id;
     125             :         uint64_t session_id;
     126             :         uint16_t session_flags;
     127       43046 :         uint16_t expected_offset = 0;
     128             :         uint16_t security_buffer_offset;
     129             :         uint16_t security_buffer_length;
     130       43046 :         uint8_t *security_buffer_data = NULL;
     131             :         struct iovec sent_iov[3];
     132             :         const uint8_t *hdr;
     133             :         const uint8_t *body;
     134             :         static const struct smb2cli_req_expected_response expected[] = {
     135             :         {
     136             :                 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
     137             :                 .body_size = 0x09
     138             :         },
     139             :         {
     140             :                 .status = NT_STATUS_OK,
     141             :                 .body_size = 0x09
     142             :         }
     143             :         };
     144             : 
     145       43046 :         status = smb2cli_req_recv(subreq, state, &state->recv_iov,
     146             :                                   expected, ARRAY_SIZE(expected));
     147       61670 :         if (!NT_STATUS_IS_OK(status) &&
     148       20130 :             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     149        3324 :                 TALLOC_FREE(subreq);
     150        3324 :                 tevent_req_nterror(req, status);
     151        3324 :                 return;
     152             :         }
     153             : 
     154       39722 :         smb2cli_req_get_sent_iov(subreq, sent_iov);
     155       39722 :         preauth_status = smb2cli_session_update_preauth(state->session, sent_iov);
     156       39722 :         TALLOC_FREE(subreq);
     157       39722 :         if (tevent_req_nterror(req, preauth_status)) {
     158           0 :                 return;
     159             :         }
     160             : 
     161       39722 :         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     162       16808 :                 preauth_status = smb2cli_session_update_preauth(state->session,
     163       16808 :                                                                 state->recv_iov);
     164       16808 :                 if (tevent_req_nterror(req, preauth_status)) {
     165           0 :                         return;
     166             :                 }
     167             :         }
     168             : 
     169       39722 :         hdr = (const uint8_t *)state->recv_iov[0].iov_base;
     170       39722 :         body = (const uint8_t *)state->recv_iov[1].iov_base;
     171             : 
     172       39722 :         session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
     173       39722 :         session_flags = SVAL(body, 2);
     174             : 
     175       39722 :         security_buffer_offset = SVAL(body, 4);
     176       39722 :         security_buffer_length = SVAL(body, 6);
     177             : 
     178       39722 :         if (security_buffer_length > 0) {
     179       39642 :                 expected_offset = SMB2_HDR_BODY + 8;
     180             :         }
     181       39722 :         if (security_buffer_offset != 0) {
     182       39722 :                 security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
     183       39722 :                 expected_offset = SMB2_HDR_BODY + 8;
     184             :         }
     185             : 
     186       39722 :         if (security_buffer_offset != expected_offset) {
     187           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     188           0 :                 return;
     189             :         }
     190       39722 :         if (security_buffer_length > state->recv_iov[2].iov_len) {
     191           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     192           0 :                 return;
     193             :         }
     194             : 
     195       39722 :         state->out_security_buffer.data = security_buffer_data;
     196       39722 :         state->out_security_buffer.length = security_buffer_length;
     197             : 
     198       39722 :         current_session_id = smb2cli_session_current_id(state->session);
     199       39722 :         if (current_session_id == 0) {
     200             :                 /* A new session was requested */
     201       23881 :                 current_session_id = session_id;
     202             :         }
     203             : 
     204       39722 :         if (current_session_id != session_id) {
     205           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     206           0 :                 return;
     207             :         }
     208             : 
     209       39722 :         smb2cli_session_set_id_and_flags(state->session,
     210             :                                          session_id, session_flags);
     211             : 
     212       39722 :         state->status = status;
     213       39722 :         tevent_req_done(req);
     214             : }
     215             : 
     216       43046 : NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
     217             :                                     TALLOC_CTX *mem_ctx,
     218             :                                     struct iovec **recv_iov,
     219             :                                     DATA_BLOB *out_security_buffer)
     220             : {
     221       38165 :         struct smb2cli_session_setup_state *state =
     222       43046 :                 tevent_req_data(req,
     223             :                 struct smb2cli_session_setup_state);
     224             :         NTSTATUS status;
     225             :         struct iovec *_tmp;
     226             : 
     227       43046 :         if (tevent_req_is_nterror(req, &status)) {
     228        3324 :                 tevent_req_received(req);
     229        3324 :                 return status;
     230             :         }
     231             : 
     232       39722 :         if (recv_iov == NULL) {
     233           8 :                 recv_iov = &_tmp;
     234             :         }
     235             : 
     236       39722 :         *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
     237             : 
     238       39722 :         *out_security_buffer = state->out_security_buffer;
     239             : 
     240             :         /*
     241             :          * Return the status from the server:
     242             :          * NT_STATUS_MORE_PROCESSING_REQUIRED or
     243             :          * NT_STATUS_OK.
     244             :          */
     245       39722 :         status = state->status;
     246       39722 :         tevent_req_received(req);
     247       39722 :         return status;
     248             : }
     249             : 
     250             : struct smb2cli_logoff_state {
     251             :         uint8_t fixed[4];
     252             : };
     253             : 
     254             : static void smb2cli_logoff_done(struct tevent_req *subreq);
     255             : 
     256          34 : struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
     257             :                                        struct tevent_context *ev,
     258             :                                        struct smbXcli_conn *conn,
     259             :                                        uint32_t timeout_msec,
     260             :                                        struct smbXcli_session *session)
     261             : {
     262             :         struct tevent_req *req, *subreq;
     263             :         struct smb2cli_logoff_state *state;
     264             : 
     265          34 :         req = tevent_req_create(mem_ctx, &state,
     266             :                                 struct smb2cli_logoff_state);
     267          34 :         if (req == NULL) {
     268           0 :                 return NULL;
     269             :         }
     270          34 :         SSVAL(state->fixed, 0, 4);
     271             : 
     272          34 :         subreq = smb2cli_req_send(state, ev,
     273             :                                   conn, SMB2_OP_LOGOFF,
     274             :                                   0, 0, /* flags */
     275             :                                   timeout_msec,
     276             :                                   NULL, /* tcon */
     277             :                                   session,
     278          34 :                                   state->fixed, sizeof(state->fixed),
     279             :                                   NULL, 0, /* dyn* */
     280             :                                   0); /* max_dyn_len */
     281          34 :         if (tevent_req_nomem(subreq, req)) {
     282           0 :                 return tevent_req_post(req, ev);
     283             :         }
     284          34 :         tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
     285          34 :         return req;
     286             : }
     287             : 
     288          34 : static void smb2cli_logoff_done(struct tevent_req *subreq)
     289             : {
     290          34 :         struct tevent_req *req =
     291          34 :                 tevent_req_callback_data(subreq,
     292             :                 struct tevent_req);
     293          34 :         struct smb2cli_logoff_state *state =
     294          34 :                 tevent_req_data(req,
     295             :                 struct smb2cli_logoff_state);
     296             :         NTSTATUS status;
     297             :         struct iovec *iov;
     298             :         static const struct smb2cli_req_expected_response expected[] = {
     299             :         {
     300             :                 .status = NT_STATUS_OK,
     301             :                 .body_size = 0x04
     302             :         }
     303             :         };
     304             : 
     305          34 :         status = smb2cli_req_recv(subreq, state, &iov,
     306             :                                   expected, ARRAY_SIZE(expected));
     307          34 :         TALLOC_FREE(subreq);
     308          34 :         if (tevent_req_nterror(req, status)) {
     309          17 :                 return;
     310             :         }
     311          17 :         tevent_req_done(req);
     312             : }
     313             : 
     314          34 : NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
     315             : {
     316          34 :         return tevent_req_simple_recv_ntstatus(req);
     317             : }
     318             : 
     319          34 : NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
     320             :                         uint32_t timeout_msec,
     321             :                         struct smbXcli_session *session)
     322             : {
     323          34 :         TALLOC_CTX *frame = talloc_stackframe();
     324             :         struct tevent_context *ev;
     325             :         struct tevent_req *req;
     326          34 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     327             : 
     328          34 :         if (smbXcli_conn_has_async_calls(conn)) {
     329             :                 /*
     330             :                  * Can't use sync call while an async call is in flight
     331             :                  */
     332           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     333           0 :                 goto fail;
     334             :         }
     335          34 :         ev = samba_tevent_context_init(frame);
     336          34 :         if (ev == NULL) {
     337           0 :                 goto fail;
     338             :         }
     339          34 :         req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
     340          34 :         if (req == NULL) {
     341           0 :                 goto fail;
     342             :         }
     343          34 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     344           0 :                 goto fail;
     345             :         }
     346          34 :         status = smb2cli_logoff_recv(req);
     347          34 :  fail:
     348          34 :         TALLOC_FREE(frame);
     349          34 :         return status;
     350             : }

Generated by: LCOV version 1.13