LCOV - code coverage report
Current view: top level - source3/smbd - smb2_tcon.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 232 304 76.3 %
Date: 2021-08-25 13:27:56 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Core SMB2 server
       4             : 
       5             :    Copyright (C) Stefan Metzmacher 2009
       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 "smbd/smbd.h"
      23             : #include "smbd/globals.h"
      24             : #include "../libcli/smb/smb_common.h"
      25             : #include "../libcli/security/security.h"
      26             : #include "auth.h"
      27             : #include "lib/param/loadparm.h"
      28             : #include "../lib/util/tevent_ntstatus.h"
      29             : 
      30             : #undef DBGC_CLASS
      31             : #define DBGC_CLASS DBGC_SMB2
      32             : 
      33             : static struct tevent_req *smbd_smb2_tree_connect_send(TALLOC_CTX *mem_ctx,
      34             :                                         struct tevent_context *ev,
      35             :                                         struct smbd_smb2_request *smb2req,
      36             :                                         uint16_t in_flags,
      37             :                                         const char *in_path);
      38             : static NTSTATUS smbd_smb2_tree_connect_recv(struct tevent_req *req,
      39             :                                             uint8_t *out_share_type,
      40             :                                             uint32_t *out_share_flags,
      41             :                                             uint32_t *out_capabilities,
      42             :                                             uint32_t *out_maximal_access,
      43             :                                             uint32_t *out_tree_id,
      44             :                                             bool *disconnect);
      45             : 
      46             : static void smbd_smb2_request_tcon_done(struct tevent_req *subreq);
      47             : 
      48       35024 : NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req)
      49             : {
      50       35024 :         struct smbXsrv_connection *xconn = req->xconn;
      51             :         const uint8_t *inbody;
      52             :         uint16_t in_flags;
      53             :         uint16_t in_path_offset;
      54             :         uint16_t in_path_length;
      55             :         DATA_BLOB in_path_buffer;
      56             :         char *in_path_string;
      57             :         size_t in_path_string_size;
      58             :         NTSTATUS status;
      59             :         bool ok;
      60             :         struct tevent_req *subreq;
      61             : 
      62       35024 :         status = smbd_smb2_request_verify_sizes(req, 0x09);
      63       35024 :         if (!NT_STATUS_IS_OK(status)) {
      64           0 :                 return smbd_smb2_request_error(req, status);
      65             :         }
      66       35024 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      67             : 
      68       35024 :         if (xconn->protocol >= PROTOCOL_SMB3_11) {
      69       32187 :                 in_flags = SVAL(inbody, 0x02);
      70             :         } else {
      71        2837 :                 in_flags = 0;
      72             :         }
      73       35024 :         in_path_offset = SVAL(inbody, 0x04);
      74       35024 :         in_path_length = SVAL(inbody, 0x06);
      75             : 
      76       35024 :         if (in_path_offset != (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
      77           0 :                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
      78             :         }
      79             : 
      80       35024 :         if (in_path_length > SMBD_SMB2_IN_DYN_LEN(req)) {
      81           0 :                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
      82             :         }
      83             : 
      84       35024 :         in_path_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
      85       35024 :         in_path_buffer.length = in_path_length;
      86             : 
      87       69658 :         ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
      88       34634 :                                    in_path_buffer.data,
      89             :                                    in_path_buffer.length,
      90             :                                    &in_path_string,
      91             :                                    &in_path_string_size);
      92       35024 :         if (!ok) {
      93           0 :                 return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
      94             :         }
      95             : 
      96       35024 :         if (in_path_buffer.length == 0) {
      97           0 :                 in_path_string_size = 0;
      98             :         }
      99             : 
     100       35024 :         if (strlen(in_path_string) != in_path_string_size) {
     101           0 :                 return smbd_smb2_request_error(req, NT_STATUS_BAD_NETWORK_NAME);
     102             :         }
     103             : 
     104       70048 :         subreq = smbd_smb2_tree_connect_send(req,
     105       35024 :                                              req->sconn->ev_ctx,
     106             :                                              req,
     107             :                                              in_flags,
     108             :                                              in_path_string);
     109       35024 :         if (subreq == NULL) {
     110           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     111             :         }
     112       35024 :         tevent_req_set_callback(subreq, smbd_smb2_request_tcon_done, req);
     113             : 
     114             :         /*
     115             :          * Avoid sending a STATUS_PENDING message, it's very likely
     116             :          * the client won't expect that.
     117             :          */
     118       35024 :         return smbd_smb2_request_pending_queue(req, subreq, 0);
     119             : }
     120             : 
     121       35024 : static void smbd_smb2_request_tcon_done(struct tevent_req *subreq)
     122             : {
     123       35024 :         struct smbd_smb2_request *req =
     124       35024 :                 tevent_req_callback_data(subreq,
     125             :                 struct smbd_smb2_request);
     126             :         uint8_t *outhdr;
     127             :         DATA_BLOB outbody;
     128       35024 :         uint8_t out_share_type = 0;
     129       35024 :         uint32_t out_share_flags = 0;
     130       35024 :         uint32_t out_capabilities = 0;
     131       35024 :         uint32_t out_maximal_access = 0;
     132       35024 :         uint32_t out_tree_id = 0;
     133       35024 :         bool disconnect = false;
     134             :         NTSTATUS status;
     135             :         NTSTATUS error;
     136             : 
     137       35024 :         status = smbd_smb2_tree_connect_recv(subreq,
     138             :                                              &out_share_type,
     139             :                                              &out_share_flags,
     140             :                                              &out_capabilities,
     141             :                                              &out_maximal_access,
     142             :                                              &out_tree_id,
     143             :                                              &disconnect);
     144       35024 :         TALLOC_FREE(subreq);
     145       35024 :         if (!NT_STATUS_IS_OK(status)) {
     146          62 :                 if (disconnect) {
     147           0 :                         smbd_server_connection_terminate(req->xconn,
     148             :                                                          nt_errstr(status));
     149           0 :                         return;
     150             :                 }
     151          62 :                 error = smbd_smb2_request_error(req, status);
     152          62 :                 if (!NT_STATUS_IS_OK(error)) {
     153           0 :                         smbd_server_connection_terminate(req->xconn,
     154             :                                                          nt_errstr(error));
     155           0 :                         return;
     156             :                 }
     157          62 :                 return;
     158             :         }
     159             : 
     160       34962 :         outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
     161             : 
     162       34962 :         outbody = smbd_smb2_generate_outbody(req, 0x10);
     163       34962 :         if (outbody.data == NULL) {
     164           0 :                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     165           0 :                 if (!NT_STATUS_IS_OK(error)) {
     166           0 :                         smbd_server_connection_terminate(req->xconn,
     167             :                                                          nt_errstr(error));
     168           0 :                         return;
     169             :                 }
     170           0 :                 return;
     171             :         }
     172             : 
     173       34962 :         SIVAL(outhdr, SMB2_HDR_TID, out_tree_id);
     174             : 
     175       34962 :         SSVAL(outbody.data, 0x00, 0x10);        /* struct size */
     176       34962 :         SCVAL(outbody.data, 0x02,
     177             :               out_share_type);                  /* share type */
     178       34962 :         SCVAL(outbody.data, 0x03, 0);           /* reserved */
     179       34962 :         SIVAL(outbody.data, 0x04,
     180             :               out_share_flags);                 /* share flags */
     181       34962 :         SIVAL(outbody.data, 0x08,
     182             :               out_capabilities);                /* capabilities */
     183       34962 :         SIVAL(outbody.data, 0x0C,
     184             :               out_maximal_access);              /* maximal access */
     185             : 
     186       34962 :         error = smbd_smb2_request_done(req, outbody, NULL);
     187       34962 :         if (!NT_STATUS_IS_OK(error)) {
     188           0 :                 smbd_server_connection_terminate(req->xconn,
     189             :                                                  nt_errstr(error));
     190           0 :                 return;
     191             :         }
     192             : }
     193             : 
     194       35024 : static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
     195             :                                        const char *in_path,
     196             :                                        uint8_t *out_share_type,
     197             :                                        uint32_t *out_share_flags,
     198             :                                        uint32_t *out_capabilities,
     199             :                                        uint32_t *out_maximal_access,
     200             :                                        uint32_t *out_tree_id,
     201             :                                        bool *disconnect)
     202             : {
     203       35024 :         const struct loadparm_substitution *lp_sub =
     204             :                 loadparm_s3_global_substitution();
     205       35024 :         struct smbXsrv_connection *conn = req->xconn;
     206       35024 :         struct smbXsrv_session *session = req->session;
     207       35024 :         struct auth_session_info *session_info =
     208       35024 :                 session->global->auth_session_info;
     209       35024 :         const char *share = in_path;
     210       35024 :         char *service = NULL;
     211       35024 :         int snum = -1;
     212             :         struct smbXsrv_tcon *tcon;
     213       35024 :         NTTIME now = timeval_to_nttime(&req->request_time);
     214       35024 :         connection_struct *compat_conn = NULL;
     215             :         NTSTATUS status;
     216       35024 :         bool encryption_desired = req->session->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED;
     217       35024 :         bool encryption_required = req->session->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED;
     218       35024 :         bool guest_session = false;
     219       35024 :         bool require_signed_tcon = false;
     220             : 
     221       35024 :         *disconnect = false;
     222             : 
     223       35024 :         if (strncmp(share, "\\\\", 2) == 0) {
     224       35024 :                 const char *p = strchr(share+2, '\\');
     225       35024 :                 if (p) {
     226       35024 :                         share = p + 1;
     227             :                 }
     228             :         }
     229             : 
     230       35024 :         DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n",
     231             :                   in_path, share));
     232             : 
     233       35024 :         if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
     234         972 :                 guest_session = true;
     235             :         }
     236             : 
     237       35024 :         if (conn->protocol >= PROTOCOL_SMB3_11 && !guest_session) {
     238       31267 :                 require_signed_tcon = true;
     239             :         }
     240             : 
     241       35022 :         if (require_signed_tcon && !req->do_encryption && !req->do_signing) {
     242           0 :                 DEBUG(1, ("smbd_smb2_tree_connect: reject request to share "
     243             :                           "[%s] as '%s\\%s' without encryption or signing. "
     244             :                           "Disconnecting.\n",
     245             :                           share,
     246             :                           req->session->global->auth_session_info->info->domain_name,
     247             :                           req->session->global->auth_session_info->info->account_name));
     248           0 :                 *disconnect = true;
     249           0 :                 return NT_STATUS_ACCESS_DENIED;
     250             :         }
     251             : 
     252       35024 :         service = talloc_strdup(talloc_tos(), share);
     253       35024 :         if(!service) {
     254           0 :                 return NT_STATUS_NO_MEMORY;
     255             :         }
     256             : 
     257       35024 :         if (!strlower_m(service)) {
     258           0 :                 DEBUG(2, ("strlower_m %s failed\n", service));
     259           0 :                 return NT_STATUS_INVALID_PARAMETER;
     260             :         }
     261             : 
     262             :         /* TODO: do more things... */
     263       35024 :         if (strequal(service,HOMES_NAME)) {
     264           0 :                 if (session->homes_snum == -1) {
     265           0 :                         DEBUG(2, ("[homes] share not available for "
     266             :                                 "user %s because it was not found "
     267             :                                 "or created at session setup "
     268             :                                 "time\n",
     269             :                                 session_info->unix_info->unix_name));
     270           0 :                         return NT_STATUS_BAD_NETWORK_NAME;
     271             :                 }
     272           0 :                 snum = session->homes_snum;
     273       35024 :         } else if ((session->homes_snum != -1)
     274       18024 :                    && strequal(service,
     275       18024 :                         lp_servicename(talloc_tos(), lp_sub, session->homes_snum))) {
     276           2 :                 snum = session->homes_snum;
     277             :         } else {
     278       35022 :                 snum = find_service(talloc_tos(), service, &service);
     279       35022 :                 if (!service) {
     280           0 :                         return NT_STATUS_NO_MEMORY;
     281             :                 }
     282             :         }
     283             : 
     284       35024 :         if (snum < 0) {
     285          14 :                 DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n",
     286             :                          service));
     287          14 :                 return NT_STATUS_BAD_NETWORK_NAME;
     288             :         }
     289             : 
     290             :         /* Handle non-DFS clients attempting connections to msdfs proxy */
     291       35010 :         if (lp_host_msdfs()) {
     292       35010 :                 char *proxy = lp_msdfs_proxy(talloc_tos(), lp_sub, snum);
     293             : 
     294       35010 :                 if ((proxy != NULL) && (*proxy != '\0')) {
     295           0 :                         DBG_NOTICE("refusing connection to dfs proxy share "
     296             :                                    "'%s' (pointing to %s)\n",
     297             :                                    service,
     298             :                                    proxy);
     299           0 :                         TALLOC_FREE(proxy);
     300           0 :                         return NT_STATUS_BAD_NETWORK_NAME;
     301             :                 }
     302       35010 :                 TALLOC_FREE(proxy);
     303             :         }
     304             : 
     305       35254 :         if ((lp_server_smb_encrypt(snum) >= SMB_ENCRYPTION_DESIRED) &&
     306         244 :             (conn->smb2.server.cipher != 0))
     307             :         {
     308         220 :                 encryption_desired = true;
     309             :         }
     310             : 
     311       35010 :         if (lp_server_smb_encrypt(snum) == SMB_ENCRYPTION_REQUIRED) {
     312         218 :                 encryption_desired = true;
     313         218 :                 encryption_required = true;
     314             :         }
     315             : 
     316       35010 :         if (guest_session && encryption_required) {
     317           0 :                 DEBUG(1,("reject guest as encryption is required for service %s\n",
     318             :                          service));
     319           0 :                 return NT_STATUS_ACCESS_DENIED;
     320             :         }
     321             : 
     322       35010 :         if (conn->smb2.server.cipher == 0) {
     323        3053 :                 if (encryption_required) {
     324          12 :                         DEBUG(1,("reject tcon with dialect[0x%04X] "
     325             :                                  "as encryption is required for service %s\n",
     326             :                                  conn->smb2.server.dialect, service));
     327          12 :                         return NT_STATUS_ACCESS_DENIED;
     328             :                 }
     329             :         }
     330             : 
     331             :         /* create a new tcon as child of the session */
     332       34998 :         status = smb2srv_tcon_create(req->session, now, &tcon);
     333       34998 :         if (!NT_STATUS_IS_OK(status)) {
     334           0 :                 return status;
     335             :         }
     336             : 
     337       34998 :         if (encryption_desired) {
     338         220 :                 tcon->global->encryption_flags |= SMBXSRV_ENCRYPTION_DESIRED;
     339             :         }
     340       34998 :         if (encryption_required) {
     341         206 :                 tcon->global->encryption_flags |= SMBXSRV_ENCRYPTION_REQUIRED;
     342             :         }
     343             : 
     344       34998 :         compat_conn = make_connection_smb2(req,
     345             :                                         tcon, snum,
     346             :                                         "???",
     347             :                                         &status);
     348       34998 :         if (compat_conn == NULL) {
     349          36 :                 TALLOC_FREE(tcon);
     350          36 :                 return status;
     351             :         }
     352             : 
     353       69534 :         tcon->global->share_name = lp_servicename(tcon->global,
     354             :                                                   lp_sub,
     355       69534 :                                                   SNUM(compat_conn));
     356       34962 :         if (tcon->global->share_name == NULL) {
     357           0 :                 conn_free(compat_conn);
     358           0 :                 TALLOC_FREE(tcon);
     359           0 :                 return NT_STATUS_NO_MEMORY;
     360             :         }
     361       69534 :         tcon->global->session_global_id =
     362       69534 :                 req->session->global->session_global_id;
     363             : 
     364       34962 :         tcon->compat = talloc_move(tcon, &compat_conn);
     365             : 
     366       34962 :         tcon->status = NT_STATUS_OK;
     367             : 
     368       34962 :         status = smbXsrv_tcon_update(tcon);
     369       34962 :         if (!NT_STATUS_IS_OK(status)) {
     370           0 :                 TALLOC_FREE(tcon);
     371           0 :                 return status;
     372             :         }
     373             : 
     374       34962 :         if (IS_PRINT(tcon->compat)) {
     375          26 :                 *out_share_type = SMB2_SHARE_TYPE_PRINT;
     376       34936 :         } else if (IS_IPC(tcon->compat)) {
     377       20771 :                 *out_share_type = SMB2_SHARE_TYPE_PIPE;
     378             :         } else {
     379       14165 :                 *out_share_type = SMB2_SHARE_TYPE_DISK;
     380             :         }
     381             : 
     382       34962 :         *out_share_flags = 0;
     383             : 
     384       34962 :         if (lp_msdfs_root(SNUM(tcon->compat)) && lp_host_msdfs()) {
     385        2542 :                 *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT);
     386        2542 :                 *out_capabilities = SMB2_SHARE_CAP_DFS;
     387             :         } else {
     388       32420 :                 *out_capabilities = 0;
     389             :         }
     390             : 
     391       34962 :         switch(lp_csc_policy(SNUM(tcon->compat))) {
     392       34572 :         case CSC_POLICY_MANUAL:
     393       34572 :                 break;
     394           0 :         case CSC_POLICY_DOCUMENTS:
     395           0 :                 *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING;
     396           0 :                 break;
     397           0 :         case CSC_POLICY_PROGRAMS:
     398           0 :                 *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING;
     399           0 :                 break;
     400           0 :         case CSC_POLICY_DISABLE:
     401           0 :                 *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING;
     402           0 :                 break;
     403           0 :         default:
     404           0 :                 break;
     405             :         }
     406             : 
     407       69914 :         if (lp_hide_unreadable(SNUM(tcon->compat)) ||
     408       34952 :             lp_hide_unwriteable_files(SNUM(tcon->compat))) {
     409          16 :                 *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM;
     410             :         }
     411             : 
     412       34962 :         if (encryption_desired) {
     413         220 :                 *out_share_flags |= SMB2_SHAREFLAG_ENCRYPT_DATA;
     414             :         }
     415             : 
     416       34962 :         *out_maximal_access = tcon->compat->share_access;
     417             : 
     418       34962 :         *out_tree_id = tcon->global->tcon_wire_id;
     419       34962 :         req->last_tid = tcon->global->tcon_wire_id;
     420             : 
     421       34962 :         return NT_STATUS_OK;
     422             : }
     423             : 
     424             : struct smbd_smb2_tree_connect_state {
     425             :         const char *in_path;
     426             :         uint8_t out_share_type;
     427             :         uint32_t out_share_flags;
     428             :         uint32_t out_capabilities;
     429             :         uint32_t out_maximal_access;
     430             :         uint32_t out_tree_id;
     431             :         bool disconnect;
     432             : };
     433             : 
     434       35024 : static struct tevent_req *smbd_smb2_tree_connect_send(TALLOC_CTX *mem_ctx,
     435             :                                         struct tevent_context *ev,
     436             :                                         struct smbd_smb2_request *smb2req,
     437             :                                         uint16_t in_flags,
     438             :                                         const char *in_path)
     439             : {
     440             :         struct tevent_req *req;
     441             :         struct smbd_smb2_tree_connect_state *state;
     442             :         NTSTATUS status;
     443             : 
     444       35024 :         req = tevent_req_create(mem_ctx, &state,
     445             :                                 struct smbd_smb2_tree_connect_state);
     446       35024 :         if (req == NULL) {
     447           0 :                 return NULL;
     448             :         }
     449       35024 :         state->in_path = in_path;
     450             : 
     451      242828 :         status = smbd_smb2_tree_connect(smb2req,
     452       34634 :                                         state->in_path,
     453       34634 :                                         &state->out_share_type,
     454       34634 :                                         &state->out_share_flags,
     455       34634 :                                         &state->out_capabilities,
     456       34634 :                                         &state->out_maximal_access,
     457       34634 :                                         &state->out_tree_id,
     458       34634 :                                         &state->disconnect);
     459       35024 :         if (tevent_req_nterror(req, status)) {
     460          62 :                 return tevent_req_post(req, ev);
     461             :         }
     462             : 
     463       34962 :         tevent_req_done(req);
     464       34962 :         return tevent_req_post(req, ev);
     465             : }
     466             : 
     467       35024 : static NTSTATUS smbd_smb2_tree_connect_recv(struct tevent_req *req,
     468             :                                             uint8_t *out_share_type,
     469             :                                             uint32_t *out_share_flags,
     470             :                                             uint32_t *out_capabilities,
     471             :                                             uint32_t *out_maximal_access,
     472             :                                             uint32_t *out_tree_id,
     473             :                                             bool *disconnect)
     474             : {
     475       35024 :         struct smbd_smb2_tree_connect_state *state =
     476       35024 :                 tevent_req_data(req,
     477             :                 struct smbd_smb2_tree_connect_state);
     478             :         NTSTATUS status;
     479             : 
     480       35024 :         if (tevent_req_is_nterror(req, &status)) {
     481          62 :                 tevent_req_received(req);
     482          62 :                 return status;
     483             :         }
     484             : 
     485       34962 :         *out_share_type = state->out_share_type;
     486       34962 :         *out_share_flags = state->out_share_flags;
     487       34962 :         *out_capabilities = state->out_capabilities;
     488       34962 :         *out_maximal_access = state->out_maximal_access;
     489       34962 :         *out_tree_id = state->out_tree_id;
     490       34962 :         *disconnect = state->disconnect;
     491             : 
     492       34962 :         tevent_req_received(req);
     493       34962 :         return NT_STATUS_OK;
     494             : }
     495             : 
     496             : static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx,
     497             :                                         struct tevent_context *ev,
     498             :                                         struct smbd_smb2_request *smb2req);
     499             : static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req);
     500             : static void smbd_smb2_request_tdis_done(struct tevent_req *subreq);
     501             : 
     502       22425 : NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req)
     503             : {
     504             :         NTSTATUS status;
     505       22425 :         struct tevent_req *subreq = NULL;
     506             : 
     507       22425 :         status = smbd_smb2_request_verify_sizes(req, 0x04);
     508       22425 :         if (!NT_STATUS_IS_OK(status)) {
     509           0 :                 return smbd_smb2_request_error(req, status);
     510             :         }
     511             : 
     512       22425 :         subreq = smbd_smb2_tdis_send(req, req->sconn->ev_ctx, req);
     513       22425 :         if (subreq == NULL) {
     514           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     515             :         }
     516       22425 :         tevent_req_set_callback(subreq, smbd_smb2_request_tdis_done, req);
     517             : 
     518             :         /*
     519             :          * Avoid sending a STATUS_PENDING message, it's very likely
     520             :          * the client won't expect that.
     521             :          */
     522       22425 :         return smbd_smb2_request_pending_queue(req, subreq, 0);
     523             : }
     524             : 
     525       22425 : static void smbd_smb2_request_tdis_done(struct tevent_req *subreq)
     526             : {
     527       22425 :         struct smbd_smb2_request *smb2req =
     528       22425 :                 tevent_req_callback_data(subreq,
     529             :                 struct smbd_smb2_request);
     530             :         DATA_BLOB outbody;
     531             :         NTSTATUS status;
     532             :         NTSTATUS error;
     533             : 
     534       22425 :         status = smbd_smb2_tdis_recv(subreq);
     535       22425 :         TALLOC_FREE(subreq);
     536       22425 :         if (!NT_STATUS_IS_OK(status)) {
     537           0 :                 error = smbd_smb2_request_error(smb2req, status);
     538           0 :                 if (!NT_STATUS_IS_OK(error)) {
     539           0 :                         smbd_server_connection_terminate(smb2req->xconn,
     540             :                                                         nt_errstr(error));
     541           0 :                         return;
     542             :                 }
     543           0 :                 return;
     544             :         }
     545             : 
     546       22425 :         outbody = smbd_smb2_generate_outbody(smb2req, 0x04);
     547       22425 :         if (outbody.data == NULL) {
     548           0 :                 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
     549           0 :                 if (!NT_STATUS_IS_OK(error)) {
     550           0 :                         smbd_server_connection_terminate(smb2req->xconn,
     551             :                                                         nt_errstr(error));
     552           0 :                         return;
     553             :                 }
     554           0 :                 return;
     555             :         }
     556             : 
     557       22425 :         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
     558       22425 :         SSVAL(outbody.data, 0x02, 0);           /* reserved */
     559             : 
     560       22425 :         error = smbd_smb2_request_done(smb2req, outbody, NULL);
     561       22425 :         if (!NT_STATUS_IS_OK(error)) {
     562           0 :                 smbd_server_connection_terminate(smb2req->xconn,
     563             :                                                 nt_errstr(error));
     564           0 :                 return;
     565             :         }
     566             : }
     567             : 
     568             : struct smbd_smb2_tdis_state {
     569             :         struct smbd_smb2_request *smb2req;
     570             :         struct tevent_queue *wait_queue;
     571             : };
     572             : 
     573             : static void smbd_smb2_tdis_wait_done(struct tevent_req *subreq);
     574             : 
     575       22425 : static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx,
     576             :                                         struct tevent_context *ev,
     577             :                                         struct smbd_smb2_request *smb2req)
     578             : {
     579             :         struct tevent_req *req;
     580             :         struct smbd_smb2_tdis_state *state;
     581             :         struct tevent_req *subreq;
     582       22425 :         struct smbXsrv_connection *xconn = NULL;
     583             : 
     584       22425 :         req = tevent_req_create(mem_ctx, &state,
     585             :                         struct smbd_smb2_tdis_state);
     586       22425 :         if (req == NULL) {
     587           0 :                 return NULL;
     588             :         }
     589       22425 :         state->smb2req = smb2req;
     590             : 
     591       22425 :         state->wait_queue = tevent_queue_create(state, "tdis_wait_queue");
     592       22425 :         if (tevent_req_nomem(state->wait_queue, req)) {
     593           0 :                 return tevent_req_post(req, ev);
     594             :         }
     595             : 
     596             :         /*
     597             :          * Make sure that no new request will be able to use this tcon.
     598             :          */
     599       22425 :         smb2req->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
     600             : 
     601       22425 :         xconn = smb2req->xconn->client->connections;
     602       44850 :         for (; xconn != NULL; xconn = xconn->next) {
     603             :                 struct smbd_smb2_request *preq;
     604             : 
     605       44856 :                 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
     606       22431 :                         if (preq == smb2req) {
     607             :                                 /* Can't cancel current request. */
     608       22425 :                                 continue;
     609             :                         }
     610           6 :                         if (preq->tcon != smb2req->tcon) {
     611             :                                 /* Request on different tcon. */
     612           0 :                                 continue;
     613             :                         }
     614             : 
     615           6 :                         if (preq->subreq != NULL) {
     616           6 :                                 tevent_req_cancel(preq->subreq);
     617             :                         }
     618             : 
     619             :                         /*
     620             :                          * Now wait until the request is finished.
     621             :                          *
     622             :                          * We don't set a callback, as we just want to block the
     623             :                          * wait queue and the talloc_free() of the request will
     624             :                          * remove the item from the wait queue.
     625             :                          */
     626           6 :                         subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
     627           6 :                         if (tevent_req_nomem(subreq, req)) {
     628           0 :                                 return tevent_req_post(req, ev);
     629             :                         }
     630             :                 }
     631             :         }
     632             : 
     633             :         /*
     634             :          * Now we add our own waiter to the end of the queue,
     635             :          * this way we get notified when all pending requests are finished
     636             :          * and send to the socket.
     637             :          */
     638       22425 :         subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
     639       22425 :         if (tevent_req_nomem(subreq, req)) {
     640           0 :                 return tevent_req_post(req, ev);
     641             :         }
     642       22425 :         tevent_req_set_callback(subreq, smbd_smb2_tdis_wait_done, req);
     643             : 
     644       22425 :         return req;
     645             : }
     646             : 
     647       22425 : static void smbd_smb2_tdis_wait_done(struct tevent_req *subreq)
     648             : {
     649       22425 :         struct tevent_req *req = tevent_req_callback_data(
     650             :                 subreq, struct tevent_req);
     651       22425 :         struct smbd_smb2_tdis_state *state = tevent_req_data(
     652             :                 req, struct smbd_smb2_tdis_state);
     653             :         NTSTATUS status;
     654             : 
     655       22425 :         tevent_queue_wait_recv(subreq);
     656       22425 :         TALLOC_FREE(subreq);
     657             : 
     658             :         /*
     659             :          * As we've been awoken, we may have changed
     660             :          * uid in the meantime. Ensure we're still
     661             :          * root (SMB2_OP_TDIS has .as_root = true).
     662             :          */
     663       22425 :         change_to_root_user();
     664             : 
     665       22425 :         status = smbXsrv_tcon_disconnect(state->smb2req->tcon,
     666       22425 :                                          state->smb2req->tcon->compat->vuid);
     667       22425 :         if (tevent_req_nterror(req, status)) {
     668           0 :                 return;
     669             :         }
     670             : 
     671             :         /* We did tear down the tcon. */
     672       22425 :         TALLOC_FREE(state->smb2req->tcon);
     673       22425 :         tevent_req_done(req);
     674             : }
     675             : 
     676       22425 : static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req)
     677             : {
     678       22425 :         return tevent_req_simple_recv_ntstatus(req);
     679             : }

Generated by: LCOV version 1.13