LCOV - code coverage report
Current view: top level - source4/smb_server/smb2 - tcon.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 163 210 77.6 %
Date: 2021-09-23 10:06:22 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB2 implementation.
       3             :    
       4             :    Copyright (C) Stefan Metzmacher      2005
       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 "libcli/smb2/smb2.h"
      22             : #include "libcli/smb2/smb2_calls.h"
      23             : #include "smb_server/smb_server.h"
      24             : #include "smb_server/smb2/smb2_server.h"
      25             : #include "samba/service_stream.h"
      26             : #include "ntvfs/ntvfs.h"
      27             : 
      28             : /*
      29             :   send an oplock break request to a client
      30             : */
      31          54 : static NTSTATUS smb2srv_send_oplock_break(void *p, struct ntvfs_handle *h, uint8_t level)
      32             : {
      33          54 :         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
      34             :                                                        struct smbsrv_handle);
      35             :         struct smb2srv_request *req;
      36             :         NTSTATUS status;
      37             : 
      38             :         /* setup a dummy request structure */
      39          54 :         req = smb2srv_init_request(handle->tcon->smb_conn);
      40          54 :         NT_STATUS_HAVE_NO_MEMORY(req);
      41             : 
      42          54 :         req->in.buffer               = talloc_array(req, uint8_t, 
      43             :                                                NBT_HDR_SIZE + SMB2_MIN_SIZE);
      44          54 :         NT_STATUS_HAVE_NO_MEMORY(req->in.buffer);
      45          54 :         req->in.size         = NBT_HDR_SIZE + SMB2_MIN_SIZE;
      46          54 :         req->in.allocated    = req->in.size;
      47             : 
      48          54 :         req->in.hdr          = req->in.buffer+ NBT_HDR_SIZE;
      49          54 :         req->in.body         = req->in.hdr        + SMB2_HDR_BODY;
      50          54 :         req->in.body_size    = req->in.size       - (SMB2_HDR_BODY+NBT_HDR_SIZE);
      51          54 :         req->in.dynamic      = NULL;
      52             : 
      53          54 :         req->seqnum          = UINT64_MAX;
      54             : 
      55          54 :         smb2srv_setup_bufinfo(req);
      56             : 
      57          54 :         SIVAL(req->in.hdr, 0,                                SMB2_MAGIC);
      58          54 :         SSVAL(req->in.hdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
      59          54 :         SSVAL(req->in.hdr, SMB2_HDR_EPOCH,           0);
      60          54 :         SIVAL(req->in.hdr, SMB2_HDR_STATUS,          0);
      61          54 :         SSVAL(req->in.hdr, SMB2_HDR_OPCODE,          SMB2_OP_BREAK);
      62          54 :         SSVAL(req->in.hdr, SMB2_HDR_CREDIT,          0);
      63          54 :         SIVAL(req->in.hdr, SMB2_HDR_FLAGS,           0);
      64          54 :         SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,    0);
      65          54 :         SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,              0);
      66          54 :         SIVAL(req->in.hdr, SMB2_HDR_PID,             0);
      67          54 :         SIVAL(req->in.hdr, SMB2_HDR_TID,             0);
      68          54 :         SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,              0);
      69          54 :         memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
      70             : 
      71          54 :         SSVAL(req->in.body, 0, 2);
      72             : 
      73          54 :         status = smb2srv_setup_reply(req, 0x18, false, 0);
      74          54 :         NT_STATUS_NOT_OK_RETURN(status);
      75             : 
      76          54 :         SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0x0000);
      77             : 
      78          54 :         SSVAL(req->out.body, 0x02, 0x0001);
      79          54 :         SIVAL(req->out.body, 0x04, 0x00000000);
      80          54 :         smb2srv_push_handle(req->out.body, 0x08, h);
      81             : 
      82          54 :         smb2srv_send_reply(req);
      83             : 
      84          54 :         return NT_STATUS_OK;
      85             : }
      86             : 
      87      188203 : struct ntvfs_handle *smb2srv_pull_handle(struct smb2srv_request *req, const uint8_t *base, unsigned int offset)
      88             : {
      89             :         struct smbsrv_tcon *tcon;
      90             :         struct smbsrv_handle *handle;
      91             :         uint32_t hid;
      92             :         uint32_t tid;
      93             :         uint64_t uid;
      94             : 
      95             :         /*
      96             :          * if there're chained requests used the cached handle
      97             :          *
      98             :          * TODO: check if this also correct when the given handle
      99             :          *       isn't all 0xFF.
     100             :          */
     101      188203 :         if (req->chained_file_handle) {
     102           0 :                 base = req->chained_file_handle;
     103           0 :                 offset = 0;
     104             :         }
     105             : 
     106      188203 :         hid = IVAL(base, offset);
     107      188203 :         tid = IVAL(base, offset + 4);
     108      188203 :         uid = BVAL(base, offset + 8);
     109             : 
     110             :         /* if it's the wildcard handle, don't waste time to search it... */
     111      188203 :         if (hid == UINT32_MAX && tid == UINT32_MAX && uid == UINT64_MAX) {
     112           0 :                 return NULL;
     113             :         }
     114             : 
     115             :         /*
     116             :          * if the (v)uid part doesn't match the given session the handle isn't
     117             :          * valid
     118             :          */
     119      188203 :         if (uid != req->session->vuid) {
     120         484 :                 return NULL;
     121             :         }
     122             : 
     123             :         /*
     124             :          * the handle can belong to a different tcon
     125             :          * as that TID in the SMB2 header says, but
     126             :          * the request should succeed nevertheless!
     127             :          *
     128             :          * because of this we put the 32 bit TID into the
     129             :          * 128 bit handle, so that we can extract the tcon from the
     130             :          * handle
     131             :          */
     132      187719 :         tcon = req->tcon;
     133      187719 :         if (tid != req->tcon->tid) {
     134           0 :                 tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
     135           0 :                 if (!tcon) {
     136           0 :                         return NULL;
     137             :                 }
     138             :         }
     139             : 
     140      187719 :         handle = smbsrv_smb2_handle_find(tcon, hid, req->request_time);
     141      187719 :         if (!handle) {
     142          12 :                 return NULL;
     143             :         }
     144             : 
     145             :         /*
     146             :          * as the smb2srv_tcon is a child object of the smb2srv_session
     147             :          * the handle belongs to the correct session!
     148             :          *
     149             :          * Note: no check is needed here for SMB2
     150             :          */
     151             : 
     152             :         /*
     153             :          * as the handle may have overwritten the tcon
     154             :          * we need to set it on the request so that the
     155             :          * correct ntvfs context will be used for the ntvfs_*() request
     156             :          *
     157             :          * TODO: check if that's correct for chained requests as well!
     158             :          */
     159      187707 :         req->tcon = tcon;
     160      187707 :         return handle->ntvfs;
     161             : }
     162             : 
     163      318547 : void smb2srv_push_handle(uint8_t *base, unsigned int offset, struct ntvfs_handle *ntvfs)
     164             : {
     165      318547 :         struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,
     166             :                                        struct smbsrv_handle);
     167             : 
     168             :         /* 
     169             :          * the handle is 128 bit on the wire
     170             :          */
     171      318547 :         SIVAL(base, offset,     handle->hid);
     172      318547 :         SIVAL(base, offset + 4, handle->tcon->tid);
     173      318547 :         SBVAL(base, offset + 8, handle->session->vuid);
     174      318547 : }
     175             : 
     176      137335 : static NTSTATUS smb2srv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h)
     177             : {
     178      137335 :         struct smb2srv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,
     179             :                                       struct smb2srv_request);
     180             :         struct smbsrv_handle *handle;
     181             :         struct ntvfs_handle *h;
     182             : 
     183      137335 :         handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);
     184      137335 :         if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;
     185             : 
     186      137335 :         h = talloc_zero(handle, struct ntvfs_handle);
     187      137335 :         if (!h) goto nomem;
     188             : 
     189             :         /* 
     190             :          * note: we don't set handle->ntvfs yet,
     191             :          *       this will be done by smbsrv_handle_make_valid()
     192             :          *       this makes sure the handle is invalid for clients
     193             :          *       until the ntvfs subsystem has made it valid
     194             :          */
     195      137335 :         h->ctx               = ntvfs->ctx;
     196      137335 :         h->session_info      = ntvfs->session_info;
     197      137335 :         h->smbpid    = ntvfs->smbpid;
     198             : 
     199      137335 :         h->frontend_data.private_data = handle;
     200             : 
     201      137335 :         *_h = h;
     202      137335 :         return NT_STATUS_OK;
     203           0 : nomem:
     204           0 :         talloc_free(handle);
     205           0 :         return NT_STATUS_NO_MEMORY;
     206             : }
     207             : 
     208      136624 : static NTSTATUS smb2srv_handle_make_valid(void *private_data, struct ntvfs_handle *h)
     209             : {
     210      136624 :         struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);
     211      136624 :         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
     212             :                                                        struct smbsrv_handle);
     213             :         /* this tells the frontend that the handle is valid */
     214      136624 :         handle->ntvfs = h;
     215             :         /* this moves the smbsrv_request to the smbsrv_tcon memory context */
     216      136624 :         talloc_steal(tcon, handle);
     217      136624 :         return NT_STATUS_OK;
     218             : }
     219             : 
     220      137171 : static void smb2srv_handle_destroy(void *private_data, struct ntvfs_handle *h)
     221             : {
     222      137171 :         struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,
     223             :                                                        struct smbsrv_handle);
     224      137171 :         talloc_free(handle);
     225      137171 : }
     226             : 
     227           0 : static struct ntvfs_handle *smb2srv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key)
     228             : {
     229           0 :         return NULL;
     230             : }
     231             : 
     232           0 : static DATA_BLOB smb2srv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx)
     233             : {
     234           0 :         return data_blob(NULL, 0);
     235             : }
     236             : 
     237        1697 : static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon *io)
     238             : {
     239             :         struct smbsrv_tcon *tcon;
     240             :         NTSTATUS status;
     241             :         enum ntvfs_type type;
     242        1697 :         const char *service = io->smb2.in.path;
     243             :         struct share_config *scfg;
     244             :         char *sharetype;
     245        1697 :         uint64_t ntvfs_caps = 0;
     246             : 
     247        1697 :         if (strncmp(service, "\\\\", 2) == 0) {
     248        1697 :                 const char *p = strchr(service+2, '\\');
     249        1697 :                 if (p) {
     250        1697 :                         service = p + 1;
     251             :                 }
     252             :         }
     253             : 
     254        1697 :         status = share_get_config(req, req->smb_conn->share_context, service, &scfg);
     255        1697 :         if (!NT_STATUS_IS_OK(status)) {
     256           0 :                 DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service));
     257           0 :                 return NT_STATUS_BAD_NETWORK_NAME;
     258             :         }
     259             : 
     260        3394 :         if (!socket_check_access(req->smb_conn->connection->socket, 
     261        1697 :                                  scfg->name, 
     262             :                                  share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW), 
     263             :                                  share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) {
     264           0 :                 return NT_STATUS_ACCESS_DENIED;
     265             :         }
     266             : 
     267             :         /* work out what sort of connection this is */
     268        1697 :         sharetype = share_string_option(req, scfg, SHARE_TYPE, "DISK");
     269        1697 :         if (sharetype && strcmp(sharetype, "IPC") == 0) {
     270        1149 :                 type = NTVFS_IPC;
     271         548 :         } else if (sharetype && strcmp(sharetype, "PRINTER") == 0) {
     272           0 :                 type = NTVFS_PRINT;
     273             :         } else {
     274         548 :                 type = NTVFS_DISK;
     275             :         }
     276        1697 :         TALLOC_FREE(sharetype);
     277             : 
     278        1697 :         tcon = smbsrv_smb2_tcon_new(req->session, scfg->name);
     279        1697 :         if (!tcon) {
     280           0 :                 DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n"));
     281           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     282             :         }
     283        1697 :         req->tcon = tcon;
     284             : 
     285        1697 :         ntvfs_caps = NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS;
     286             : 
     287             :         /* init ntvfs function pointers */
     288        7137 :         status = ntvfs_init_connection(tcon, scfg, type,
     289        1697 :                                        req->smb_conn->negotiate.protocol,
     290             :                                        ntvfs_caps,
     291        1697 :                                        req->smb_conn->connection->event.ctx,
     292        1697 :                                        req->smb_conn->connection->msg_ctx,
     293        1697 :                                        req->smb_conn->lp_ctx,
     294        1697 :                                        req->smb_conn->connection->server_id,
     295             :                                        &tcon->ntvfs);
     296        1697 :         if (!NT_STATUS_IS_OK(status)) {
     297           0 :                 DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n", 
     298             :                           scfg->name));
     299           0 :                 goto failed;
     300             :         }
     301             : 
     302        1697 :         status = ntvfs_set_oplock_handler(tcon->ntvfs, smb2srv_send_oplock_break, tcon);
     303        1697 :         if (!NT_STATUS_IS_OK(status)) {
     304           0 :                 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n"));
     305           0 :                 goto failed;
     306             :         }
     307             : 
     308        1697 :         status = ntvfs_set_addresses(tcon->ntvfs,
     309        1697 :                                      req->smb_conn->connection->local_address,
     310        1697 :                                      req->smb_conn->connection->remote_address);
     311        1697 :         if (!NT_STATUS_IS_OK(status)) {
     312           0 :                 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the address!\n"));
     313           0 :                 goto failed;
     314             :         }
     315             : 
     316        1697 :         status = ntvfs_set_handle_callbacks(tcon->ntvfs,
     317             :                                             smb2srv_handle_create_new,
     318             :                                             smb2srv_handle_make_valid,
     319             :                                             smb2srv_handle_destroy,
     320             :                                             smb2srv_handle_search_by_wire_key,
     321             :                                             smb2srv_handle_get_wire_key,
     322             :                                             tcon);
     323        1697 :         if (!NT_STATUS_IS_OK(status)) {
     324           0 :                 DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n"));
     325           0 :                 goto failed;
     326             :         }
     327             : 
     328        3394 :         req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
     329        1697 :                                           req->session->session_info,
     330        1697 :                                           SVAL(req->in.hdr, SMB2_HDR_PID),
     331             :                                           req->request_time,
     332             :                                           req, NULL, 0);
     333        1697 :         if (!req->ntvfs) {
     334           0 :                 status = NT_STATUS_NO_MEMORY;
     335           0 :                 goto failed;
     336             :         }
     337             : 
     338        1697 :         io->smb2.out.share_type        = (unsigned)type; /* 1 - DISK, 2 - Print, 3 - IPC */
     339        1697 :         io->smb2.out.reserved          = 0;
     340        1697 :         io->smb2.out.flags     = 0x00000000;
     341        1697 :         io->smb2.out.capabilities = 0;
     342        1697 :         io->smb2.out.access_mask  = SEC_RIGHTS_FILE_ALL;
     343             : 
     344        1697 :         io->smb2.out.tid     = tcon->tid;
     345             : 
     346             :         /* Invoke NTVFS connection hook */
     347        1697 :         status = ntvfs_connect(req->ntvfs, io);
     348        1697 :         if (!NT_STATUS_IS_OK(status)) {
     349           0 :                 DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed: %s!\n", nt_errstr(status)));
     350           0 :                 goto failed;
     351             :         }
     352             : 
     353        1697 :         return NT_STATUS_OK;
     354             : 
     355           0 : failed:
     356           0 :         req->tcon = NULL;
     357           0 :         talloc_free(tcon);
     358           0 :         return status;
     359             : }
     360             : 
     361        1697 : static void smb2srv_tcon_send(struct smb2srv_request *req, union smb_tcon *io)
     362             : {
     363        1697 :         if (!NT_STATUS_IS_OK(req->status)) {
     364           0 :                 smb2srv_send_error(req, req->status);
     365           0 :                 return;
     366             :         }
     367             : 
     368        1697 :         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, false, 0));
     369             : 
     370        1697 :         SIVAL(req->out.hdr,  SMB2_HDR_TID,   io->smb2.out.tid);
     371             : 
     372        1697 :         SCVAL(req->out.body, 0x02,           io->smb2.out.share_type);
     373        1697 :         SCVAL(req->out.body, 0x03,           io->smb2.out.reserved);
     374        1697 :         SIVAL(req->out.body, 0x04,           io->smb2.out.flags);
     375        1697 :         SIVAL(req->out.body, 0x08,           io->smb2.out.capabilities);
     376        1697 :         SIVAL(req->out.body, 0x0C,           io->smb2.out.access_mask);
     377             : 
     378        1697 :         smb2srv_send_reply(req);
     379             : }
     380             : 
     381        1697 : void smb2srv_tcon_recv(struct smb2srv_request *req)
     382             : {
     383             :         union smb_tcon *io;
     384             : 
     385        1697 :         SMB2SRV_CHECK_BODY_SIZE(req, 0x08, true);
     386        1697 :         SMB2SRV_TALLOC_IO_PTR(io, union smb_tcon);
     387             : 
     388        1697 :         io->smb2.level               = RAW_TCON_SMB2;
     389        1697 :         io->smb2.in.reserved = SVAL(req->in.body, 0x02);
     390        1697 :         SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x04, &io->smb2.in.path));
     391             : 
     392             :         /* the VFS backend does not yet handle NULL paths */
     393        1697 :         if (io->smb2.in.path == NULL) {
     394           0 :                 io->smb2.in.path = "";
     395             :         }
     396             : 
     397        1697 :         req->status = smb2srv_tcon_backend(req, io);
     398             : 
     399        1697 :         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
     400           0 :                 talloc_free(req);
     401           0 :                 return;
     402             :         }
     403        1697 :         smb2srv_tcon_send(req, io);
     404             : }
     405             : 
     406         439 : static NTSTATUS smb2srv_tdis_backend(struct smb2srv_request *req)
     407             : {
     408             :         /* TODO: call ntvfs backends to close file of this tcon */
     409         439 :         talloc_free(req->tcon);
     410         439 :         req->tcon = NULL;
     411         439 :         return NT_STATUS_OK;
     412             : }
     413             : 
     414         439 : static void smb2srv_tdis_send(struct smb2srv_request *req)
     415             : {
     416             :         NTSTATUS status;
     417             : 
     418         439 :         if (NT_STATUS_IS_ERR(req->status)) {
     419           0 :                 smb2srv_send_error(req, req->status);
     420           0 :                 return;
     421             :         }
     422             : 
     423         439 :         status = smb2srv_setup_reply(req, 0x04, false, 0);
     424         439 :         if (!NT_STATUS_IS_OK(status)) {
     425           0 :                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
     426           0 :                 talloc_free(req);
     427           0 :                 return;
     428             :         }
     429             : 
     430         439 :         SSVAL(req->out.body, 0x02, 0);
     431             : 
     432         439 :         smb2srv_send_reply(req);
     433             : }
     434             : 
     435         439 : void smb2srv_tdis_recv(struct smb2srv_request *req)
     436             : {
     437         439 :         SMB2SRV_CHECK_BODY_SIZE(req, 0x04, false);
     438             : 
     439         439 :         req->status = smb2srv_tdis_backend(req);
     440             : 
     441         439 :         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
     442           0 :                 talloc_free(req);
     443           0 :                 return;
     444             :         }
     445         439 :         smb2srv_tdis_send(req);
     446             : }

Generated by: LCOV version 1.13