LCOV - code coverage report
Current view: top level - source4/smb_server/smb2 - sesssetup.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 121 169 71.6 %
Date: 2024-04-21 15:09:00 Functions: 8 8 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 <tevent.h>
      23             : #include "auth/gensec/gensec.h"
      24             : #include "auth/auth.h"
      25             : #include "libcli/smb2/smb2.h"
      26             : #include "libcli/smb2/smb2_calls.h"
      27             : #include "smb_server/smb_server.h"
      28             : #include "smb_server/smb2/smb2_server.h"
      29             : #include "samba/service_stream.h"
      30             : #include "lib/stream/packet.h"
      31             : 
      32        2692 : static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sesssetup *io)
      33             : {
      34        2692 :         if (NT_STATUS_IS_OK(req->status)) {
      35             :                 /* nothing */
      36        1089 :         } else if (NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
      37             :                 /* nothing */
      38             :         } else {
      39         505 :                 smb2srv_send_error(req, req->status);
      40         505 :                 return;
      41             :         }
      42             : 
      43        2187 :         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, io->smb2.out.secblob.length));
      44             : 
      45        2187 :         SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID,     io->smb2.out.uid);
      46             : 
      47        2187 :         SSVAL(req->out.body, 0x02, io->smb2.out.session_flags);
      48        2187 :         SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x04, io->smb2.out.secblob));
      49             : 
      50        2187 :         smb2srv_send_reply(req);
      51             : }
      52             : 
      53             : struct smb2srv_sesssetup_callback_ctx {
      54             :         struct smb2srv_request *req;
      55             :         union smb_sesssetup *io;
      56             :         struct smbsrv_session *smb_sess;
      57             : };
      58             : 
      59        2692 : static void smb2srv_sesssetup_callback(struct tevent_req *subreq)
      60             : {
      61        2692 :         struct smb2srv_sesssetup_callback_ctx *ctx = tevent_req_callback_data(subreq,
      62             :                                                      struct smb2srv_sesssetup_callback_ctx);
      63        2692 :         struct smb2srv_request *req = ctx->req;
      64        2692 :         union smb_sesssetup *io = ctx->io;
      65        2692 :         struct smbsrv_session *smb_sess = ctx->smb_sess;
      66        2692 :         struct auth_session_info *session_info = NULL;
      67           0 :         enum security_user_level user_level;
      68           0 :         NTSTATUS status;
      69             : 
      70        2692 :         packet_recv_enable(req->smb_conn->packet);
      71             : 
      72        2692 :         status = gensec_update_recv(subreq, req, &io->smb2.out.secblob);
      73        2692 :         TALLOC_FREE(subreq);
      74        2692 :         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
      75         584 :                 goto done;
      76        2108 :         } else if (!NT_STATUS_IS_OK(status)) {
      77         505 :                 goto failed;
      78             :         }
      79             : 
      80        1603 :         status = gensec_session_info(smb_sess->gensec_ctx, smb_sess, &session_info);
      81        1603 :         if (!NT_STATUS_IS_OK(status)) {
      82           0 :                 goto failed;
      83             :         }
      84             : 
      85             :         /* Ensure this is marked as a 'real' vuid, not one
      86             :          * simply valid for the session setup leg */
      87        1603 :         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
      88        1603 :         if (!NT_STATUS_IS_OK(status)) {
      89           0 :                 goto failed;
      90             :         }
      91        1603 :         req->session = smb_sess;
      92             : 
      93        1603 :         user_level = security_session_user_level(smb_sess->session_info, NULL);
      94        1603 :         if (user_level >= SECURITY_USER) {
      95        1556 :                 if (smb_sess->smb2_signing.required) {
      96             :                         /* activate smb2 signing on the session */
      97        1103 :                         smb_sess->smb2_signing.active = true;
      98             :                 }
      99             :                 /* we need to sign the session setup response */
     100        1556 :                 req->is_signed = true;
     101             :         }
     102             : 
     103          47 : done:
     104        2187 :         io->smb2.out.uid = smb_sess->vuid;
     105        2692 : failed:
     106        2692 :         req->status = nt_status_squash(status);
     107        2692 :         smb2srv_sesssetup_send(req, io);
     108        2692 :         if (!NT_STATUS_IS_OK(status) && !
     109        1089 :             NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     110         505 :                 talloc_free(smb_sess);
     111             :         }
     112        2692 : }
     113             : 
     114        2692 : static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_sesssetup *io)
     115             : {
     116           0 :         NTSTATUS status;
     117           0 :         struct smb2srv_sesssetup_callback_ctx *callback_ctx;
     118        2692 :         struct smbsrv_session *smb_sess = NULL;
     119           0 :         uint64_t vuid;
     120           0 :         struct tevent_req *subreq;
     121             : 
     122        2692 :         io->smb2.out.session_flags = 0;
     123        2692 :         io->smb2.out.uid     = 0;
     124        2692 :         io->smb2.out.secblob = data_blob(NULL, 0);
     125             : 
     126        2692 :         vuid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
     127             : 
     128             :         /*
     129             :          * only when we got '0' we should allocate a new session
     130             :          */
     131        2692 :         if (vuid == 0) {
     132           0 :                 struct gensec_security *gensec_ctx;
     133           0 :                 struct tsocket_address *remote_address, *local_address;
     134             : 
     135        2108 :                 status = samba_server_gensec_start(req,
     136        2108 :                                                    req->smb_conn->connection->event.ctx,
     137        2108 :                                                    req->smb_conn->connection->msg_ctx,
     138        2108 :                                                    req->smb_conn->lp_ctx,
     139        2108 :                                                    req->smb_conn->negotiate.server_credentials,
     140             :                                                    "cifs",
     141             :                                                    &gensec_ctx);
     142        2108 :                 if (!NT_STATUS_IS_OK(status)) {
     143           0 :                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
     144           0 :                         goto failed;
     145             :                 }
     146             : 
     147        2108 :                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
     148        2108 :                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SMB_TRANSPORT);
     149             : 
     150        2108 :                 remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
     151             :                                                         req);
     152        2108 :                 if (!remote_address) {
     153           0 :                         status = NT_STATUS_INTERNAL_ERROR;
     154           0 :                         DBG_ERR("Failed to obtain remote address\n");
     155           0 :                         goto failed;
     156             :                 }
     157             : 
     158        2108 :                 status = gensec_set_remote_address(gensec_ctx,
     159             :                                                    remote_address);
     160        2108 :                 if (!NT_STATUS_IS_OK(status)) {
     161           0 :                         DBG_ERR("Failed to set remote address\n");
     162           0 :                         goto failed;
     163             :                 }
     164             : 
     165        2108 :                 local_address = socket_get_local_addr(req->smb_conn->connection->socket,
     166             :                                                       req);
     167        2108 :                 if (!local_address) {
     168           0 :                         status = NT_STATUS_INTERNAL_ERROR;
     169           0 :                         DBG_ERR("Failed to obtain local address\n");
     170           0 :                         goto failed;
     171             :                 }
     172             : 
     173        2108 :                 status = gensec_set_local_address(gensec_ctx,
     174             :                                                   local_address);
     175        2108 :                 if (!NT_STATUS_IS_OK(status)) {
     176           0 :                         DBG_ERR("Failed to set local address\n");
     177           0 :                         goto failed;
     178             :                 }
     179             : 
     180        2108 :                 status = gensec_set_target_service_description(gensec_ctx,
     181             :                                                                "SMB2");
     182             : 
     183        2108 :                 if (!NT_STATUS_IS_OK(status)) {
     184           0 :                         DBG_ERR("Failed to set service description\n");
     185           0 :                         goto failed;
     186             :                 }
     187             : 
     188        2108 :                 status = gensec_start_mech_by_oid(gensec_ctx, GENSEC_OID_SPNEGO);
     189        2108 :                 if (!NT_STATUS_IS_OK(status)) {
     190           0 :                         DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
     191           0 :                         goto failed;
     192             :                 }
     193             : 
     194             :                 /* allocate a new session */
     195        2108 :                 smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx);
     196        2108 :                 if (!smb_sess) {
     197           0 :                         status = NT_STATUS_INSUFFICIENT_RESOURCES;
     198           0 :                         goto failed;
     199             :                 }
     200        2108 :                 status = smbsrv_smb2_init_tcons(smb_sess);
     201        2108 :                 if (!NT_STATUS_IS_OK(status)) {
     202           0 :                         goto failed;
     203             :                 }
     204             :         } else {
     205             :                 /* lookup an existing session */
     206         584 :                 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
     207             :         }
     208             : 
     209        2692 :         if (!smb_sess) {
     210           0 :                 status = NT_STATUS_USER_SESSION_DELETED;
     211           0 :                 goto failed;
     212             :         }
     213             : 
     214        2692 :         if (smb_sess->session_info) {
     215             :                 /* see WSPP test suite - test 11 */
     216           0 :                 status = NT_STATUS_REQUEST_NOT_ACCEPTED;
     217           0 :                 goto failed;
     218             :         }
     219             : 
     220        2692 :         if (!smb_sess->gensec_ctx) {
     221           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     222           0 :                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
     223           0 :                 goto failed;
     224             :         }
     225             : 
     226        2692 :         callback_ctx = talloc(req, struct smb2srv_sesssetup_callback_ctx);
     227        2692 :         if (!callback_ctx) goto nomem;
     228        2692 :         callback_ctx->req    = req;
     229        2692 :         callback_ctx->io     = io;
     230        2692 :         callback_ctx->smb_sess       = smb_sess;
     231             : 
     232        2692 :         subreq = gensec_update_send(callback_ctx,
     233        2692 :                                     req->smb_conn->connection->event.ctx,
     234             :                                     smb_sess->gensec_ctx,
     235             :                                     io->smb2.in.secblob);
     236        2692 :         if (!subreq) goto nomem;
     237        2692 :         tevent_req_set_callback(subreq, smb2srv_sesssetup_callback, callback_ctx);
     238             : 
     239             :         /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
     240             :            This is deliberate as windows does not set it even when it does 
     241             :            set SMB2_NEGOTIATE_SIGNING_REQUIRED */
     242        2692 :         if (io->smb2.in.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
     243        1217 :                 smb_sess->smb2_signing.required = true;
     244             :         }
     245             : 
     246             :         /* disable receipt of more packets on this socket until we've
     247             :            finished with the session setup. This avoids a problem with
     248             :            crashes if we get EOF on the socket while processing a session
     249             :            setup */
     250        2692 :         packet_recv_disable(req->smb_conn->packet);
     251             : 
     252        2692 :         return;
     253           0 : nomem:
     254           0 :         status = NT_STATUS_NO_MEMORY;
     255           0 : failed:
     256           0 :         talloc_free(smb_sess);
     257           0 :         req->status = nt_status_squash(status);
     258           0 :         smb2srv_sesssetup_send(req, io);
     259             : }
     260             : 
     261        2692 : void smb2srv_sesssetup_recv(struct smb2srv_request *req)
     262             : {
     263           0 :         union smb_sesssetup *io;
     264             : 
     265        2692 :         SMB2SRV_CHECK_BODY_SIZE(req, 0x18, true);
     266        2692 :         SMB2SRV_TALLOC_IO_PTR(io, union smb_sesssetup);
     267             : 
     268        2692 :         io->smb2.level                      = RAW_SESSSETUP_SMB2;
     269        2692 :         io->smb2.in.vc_number               = CVAL(req->in.body, 0x02);
     270        2692 :         io->smb2.in.security_mode      = CVAL(req->in.body, 0x03);
     271        2692 :         io->smb2.in.capabilities       = IVAL(req->in.body, 0x04);
     272        2692 :         io->smb2.in.channel            = IVAL(req->in.body, 0x08);
     273        2692 :         io->smb2.in.previous_sessionid = BVAL(req->in.body, 0x10);
     274        2692 :         SMB2SRV_CHECK(smb2_pull_o16s16_blob(&req->in, io, req->in.body+0x0C, &io->smb2.in.secblob));
     275             : 
     276        2692 :         smb2srv_sesssetup_backend(req, io);
     277             : }
     278             : 
     279           4 : static int smb2srv_cleanup_session_destructor(struct smbsrv_session **session)
     280             : {
     281             :         /* TODO: call ntvfs backends to close file of this session */
     282           4 :         DEBUG(0,("free session[%p]\n", *session));
     283           4 :         talloc_free(*session);
     284           4 :         return 0;
     285             : }
     286             : 
     287           4 : static NTSTATUS smb2srv_logoff_backend(struct smb2srv_request *req)
     288             : {
     289           0 :         struct smbsrv_session **session_ptr;
     290             : 
     291             :         /* we need to destroy the session after sending the reply */
     292           4 :         session_ptr = talloc(req, struct smbsrv_session *);
     293           4 :         NT_STATUS_HAVE_NO_MEMORY(session_ptr);
     294             : 
     295           4 :         *session_ptr = req->session;
     296           4 :         talloc_set_destructor(session_ptr, smb2srv_cleanup_session_destructor);
     297             : 
     298           4 :         return NT_STATUS_OK;
     299             : }
     300             : 
     301           4 : static void smb2srv_logoff_send(struct smb2srv_request *req)
     302             : {
     303           4 :         if (NT_STATUS_IS_ERR(req->status)) {
     304           0 :                 smb2srv_send_error(req, req->status);
     305           0 :                 return;
     306             :         }
     307             : 
     308           4 :         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x04, false, 0));
     309             : 
     310           4 :         SSVAL(req->out.body, 0x02, 0);
     311             : 
     312           4 :         smb2srv_send_reply(req);
     313             : }
     314             : 
     315           4 : void smb2srv_logoff_recv(struct smb2srv_request *req)
     316             : {
     317           4 :         SMB2SRV_CHECK_BODY_SIZE(req, 0x04, false);
     318             : 
     319           4 :         req->status = smb2srv_logoff_backend(req);
     320             : 
     321           4 :         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
     322           0 :                 talloc_free(req);
     323           0 :                 return;
     324             :         }
     325           4 :         smb2srv_logoff_send(req);
     326             : }

Generated by: LCOV version 1.14