LCOV - code coverage report
Current view: top level - source3/libsmb - clientgen.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 202 260 77.7 %
Date: 2021-09-23 10:06:22 Functions: 23 25 92.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    SMB client generic functions
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) Jeremy Allison 2007.
       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 "libsmb/libsmb.h"
      23             : #include "../lib/util/tevent_ntstatus.h"
      24             : #include "../libcli/smb/smb_signing.h"
      25             : #include "../libcli/smb/smb_seal.h"
      26             : #include "async_smb.h"
      27             : #include "../libcli/smb/smbXcli_base.h"
      28             : #include "../libcli/smb/smb2_negotiate_context.h"
      29             : #include "../librpc/ndr/libndr.h"
      30             : #include "../include/client.h"
      31             : 
      32             : /****************************************************************************
      33             :  Change the timeout (in milliseconds).
      34             : ****************************************************************************/
      35             : 
      36        9933 : unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout)
      37             : {
      38        9933 :         unsigned int old_timeout = cli->timeout;
      39        9933 :         cli->timeout = timeout;
      40        9933 :         return old_timeout;
      41             : }
      42             : 
      43             : /****************************************************************************
      44             :  Set the 'backup_intent' flag.
      45             : ****************************************************************************/
      46             : 
      47          20 : bool cli_set_backup_intent(struct cli_state *cli, bool flag)
      48             : {
      49          20 :         bool old_state = cli->backup_intent;
      50          20 :         cli->backup_intent = flag;
      51          20 :         return old_state;
      52             : }
      53             : 
      54             : /****************************************************************************
      55             :  Initialise a client structure. Always returns a talloc'ed struct.
      56             :  Set the signing state (used from the command line).
      57             : ****************************************************************************/
      58             : 
      59             : struct GUID cli_state_client_guid;
      60             : 
      61       14964 : struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx,
      62             :                                    int fd,
      63             :                                    const char *remote_name,
      64             :                                    int signing_state, int flags)
      65             : {
      66       14964 :         struct cli_state *cli = NULL;
      67       14964 :         bool use_spnego = lp_client_use_spnego();
      68       14964 :         bool force_dos_errors = false;
      69       14964 :         bool force_ascii = false;
      70       14964 :         bool use_level_II_oplocks = false;
      71       14964 :         uint32_t smb1_capabilities = 0;
      72       14964 :         uint32_t smb2_capabilities = 0;
      73       13947 :         struct smb311_capabilities smb3_capabilities =
      74        1017 :                 smb311_capabilities_parse("client",
      75       14964 :                         lp_client_smb3_signing_algorithms(),
      76       14964 :                         lp_client_smb3_encryption_algorithms());
      77             :         struct GUID client_guid;
      78             : 
      79       14964 :         if (!GUID_all_zero(&cli_state_client_guid)) {
      80           0 :                 client_guid = cli_state_client_guid;
      81             :         } else {
      82       14964 :                 client_guid = GUID_random();
      83             :         }
      84             : 
      85             :         /* Check the effective uid - make sure we are not setuid */
      86       14964 :         if (is_setuid_root()) {
      87           0 :                 DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
      88           0 :                 return NULL;
      89             :         }
      90             : 
      91       14964 :         cli = talloc_zero(mem_ctx, struct cli_state);
      92       14964 :         if (!cli) {
      93           0 :                 return NULL;
      94             :         }
      95             : 
      96       14964 :         cli->server_domain = talloc_strdup(cli, "");
      97       14964 :         if (!cli->server_domain) {
      98           0 :                 goto error;
      99             :         }
     100       14964 :         cli->server_os = talloc_strdup(cli, "");
     101       14964 :         if (!cli->server_os) {
     102           0 :                 goto error;
     103             :         }
     104       14964 :         cli->server_type = talloc_strdup(cli, "");
     105       14964 :         if (!cli->server_type) {
     106           0 :                 goto error;
     107             :         }
     108             : 
     109       14964 :         cli->raw_status = NT_STATUS_INTERNAL_ERROR;
     110       14964 :         cli->map_dos_errors = true; /* remove this */
     111       14964 :         cli->timeout = CLIENT_TIMEOUT;
     112             : 
     113             :         /* Set the CLI_FORCE_DOSERR environment variable to test
     114             :            client routines using DOS errors instead of STATUS32
     115             :            ones.  This intended only as a temporary hack. */    
     116       14964 :         if (getenv("CLI_FORCE_DOSERR")) {
     117           0 :                 force_dos_errors = true;
     118             :         }
     119       14964 :         if (flags & CLI_FULL_CONNECTION_FORCE_DOS_ERRORS) {
     120           0 :                 force_dos_errors = true;
     121             :         }
     122             : 
     123       14964 :         if (getenv("CLI_FORCE_ASCII")) {
     124           0 :                 force_ascii = true;
     125             :         }
     126       14964 :         if (!lp_unicode()) {
     127           0 :                 force_ascii = true;
     128             :         }
     129       14964 :         if (flags & CLI_FULL_CONNECTION_FORCE_ASCII) {
     130           0 :                 force_ascii = true;
     131             :         }
     132             : 
     133       14964 :         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
     134           0 :                 use_spnego = false;
     135             :         }
     136             : 
     137       14964 :         if (flags & CLI_FULL_CONNECTION_OPLOCKS) {
     138           8 :                 cli->use_oplocks = true;
     139             :         }
     140       14964 :         if (flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) {
     141           8 :                 use_level_II_oplocks = true;
     142             :         }
     143             : 
     144       14964 :         if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
     145             :                 /*
     146             :                  * Ensure for IPC/RPC the default is to require
     147             :                  * signing unless explicitly turned off by the
     148             :                  * administrator.
     149             :                  */
     150           9 :                 signing_state = lp_client_ipc_signing();
     151             :         }
     152             : 
     153       14964 :         if (signing_state == SMB_SIGNING_DEFAULT) {
     154       11619 :                 signing_state = lp_client_signing();
     155             :         }
     156             : 
     157       14964 :         smb1_capabilities = 0;
     158       14964 :         smb1_capabilities |= CAP_LARGE_FILES;
     159       14964 :         smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
     160       14964 :         smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
     161       14964 :         smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS;
     162       14964 :         smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
     163       14964 :         smb1_capabilities |= CAP_LWIO;
     164             : 
     165       14964 :         if (!force_dos_errors) {
     166       14964 :                 smb1_capabilities |= CAP_STATUS32;
     167             :         }
     168             : 
     169       14964 :         if (!force_ascii) {
     170       14964 :                 smb1_capabilities |= CAP_UNICODE;
     171             :         }
     172             : 
     173       14964 :         if (use_spnego) {
     174       14753 :                 smb1_capabilities |= CAP_EXTENDED_SECURITY;
     175             :         }
     176             : 
     177       14964 :         if (use_level_II_oplocks) {
     178           8 :                 smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
     179             :         }
     180             : 
     181       14964 :         smb2_capabilities = SMB2_CAP_ALL;
     182             : 
     183       14964 :         cli->conn = smbXcli_conn_create(cli, fd, remote_name,
     184             :                                         signing_state,
     185             :                                         smb1_capabilities,
     186             :                                         &client_guid,
     187             :                                         smb2_capabilities,
     188             :                                         &smb3_capabilities);
     189       14964 :         if (cli->conn == NULL) {
     190           0 :                 goto error;
     191             :         }
     192             : 
     193       14964 :         cli->smb1.pid = (uint32_t)getpid();
     194       14964 :         cli->smb1.vc_num = cli->smb1.pid;
     195       14964 :         cli->smb1.session = smbXcli_session_create(cli, cli->conn);
     196       14964 :         if (cli->smb1.session == NULL) {
     197           0 :                 goto error;
     198             :         }
     199             : 
     200       14964 :         cli->initialised = 1;
     201       14964 :         return cli;
     202             : 
     203             :         /* Clean up after malloc() error */
     204             : 
     205           0 :  error:
     206             : 
     207           0 :         TALLOC_FREE(cli);
     208           0 :         return NULL;
     209             : }
     210             : 
     211             : /****************************************************************************
     212             :  Close all pipes open on this session.
     213             : ****************************************************************************/
     214             : 
     215       11936 : static void cli_nt_pipes_close(struct cli_state *cli)
     216             : {
     217       23414 :         while (cli->pipe_list != NULL) {
     218             :                 /*
     219             :                  * No TALLOC_FREE here!
     220             :                  */
     221         521 :                 talloc_free(cli->pipe_list);
     222             :         }
     223       11936 : }
     224             : 
     225             : /****************************************************************************
     226             :  Shutdown a client structure.
     227             : ****************************************************************************/
     228             : 
     229       11936 : static void _cli_shutdown(struct cli_state *cli)
     230             : {
     231       11936 :         cli_nt_pipes_close(cli);
     232             : 
     233             :         /*
     234             :          * tell our peer to free his resources.  Without this, when an
     235             :          * application attempts to do a graceful shutdown and calls
     236             :          * smbc_free_context() to clean up all connections, some connections
     237             :          * can remain active on the peer end, until some (long) timeout period
     238             :          * later.  This tree disconnect forces the peer to clean up, since the
     239             :          * connection will be going away.
     240             :          */
     241       11936 :         if (cli_state_has_tcon(cli)) {
     242       10816 :                 cli_tdis(cli);
     243             :         }
     244             : 
     245       11936 :         smbXcli_conn_disconnect(cli->conn, NT_STATUS_OK);
     246             : 
     247       11936 :         TALLOC_FREE(cli);
     248       11936 : }
     249             : 
     250       11936 : void cli_shutdown(struct cli_state *cli)
     251             : {
     252             :         struct cli_state *cli_head;
     253       11936 :         if (cli == NULL) {
     254           0 :                 return;
     255             :         }
     256       11950 :         DLIST_HEAD(cli, cli_head);
     257       11936 :         if (cli_head == cli) {
     258             :                 /*
     259             :                  * head of a DFS list, shutdown all subsidiary DFS
     260             :                  * connections.
     261             :                  */
     262             :                 struct cli_state *p, *next;
     263             : 
     264       11746 :                 for (p = cli_head->next; p; p = next) {
     265           0 :                         next = p->next;
     266           0 :                         DLIST_REMOVE(cli_head, p);
     267           0 :                         _cli_shutdown(p);
     268             :                 }
     269             :         } else {
     270         190 :                 DLIST_REMOVE(cli_head, cli);
     271             :         }
     272             : 
     273       11936 :         _cli_shutdown(cli);
     274             : }
     275             : 
     276        5981 : uint16_t cli_state_get_vc_num(struct cli_state *cli)
     277             : {
     278        5981 :         return cli->smb1.vc_num;
     279             : }
     280             : 
     281             : /****************************************************************************
     282             :  Set the PID to use for smb messages. Return the old pid.
     283             : ****************************************************************************/
     284             : 
     285          89 : uint32_t cli_setpid(struct cli_state *cli, uint32_t pid)
     286             : {
     287          89 :         uint32_t ret = cli->smb1.pid;
     288          89 :         cli->smb1.pid = pid;
     289          89 :         return ret;
     290             : }
     291             : 
     292        4650 : uint32_t cli_getpid(struct cli_state *cli)
     293             : {
     294        4650 :         return cli->smb1.pid;
     295             : }
     296             : 
     297           0 : bool cli_state_is_encryption_on(struct cli_state *cli)
     298             : {
     299           0 :         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
     300           0 :                 return smb1cli_conn_encryption_on(cli->conn);
     301             :         }
     302             : 
     303           0 :         if (cli->smb2.tcon == NULL) {
     304           0 :                 return false;
     305             :         }
     306             : 
     307           0 :         return smb2cli_tcon_is_encryption_on(cli->smb2.tcon);
     308             : }
     309             : 
     310       28598 : bool cli_state_has_tcon(struct cli_state *cli)
     311             : {
     312             :         uint32_t tid;
     313       28598 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     314       22986 :                 if (cli->smb2.tcon == NULL) {
     315        6537 :                         return false;
     316             :                 }
     317       16449 :                 tid = cli_state_get_tid(cli);
     318       16449 :                 if (tid == UINT32_MAX) {
     319           0 :                         return false;
     320             :                 }
     321             :         } else {
     322        5612 :                 if (cli->smb1.tcon == NULL) {
     323        3100 :                         return false;
     324             :                 }
     325        2512 :                 tid = cli_state_get_tid(cli);
     326        2512 :                 if (tid == UINT16_MAX) {
     327          11 :                         return false;
     328             :                 }
     329             :         }
     330       18950 :         return true;
     331             : }
     332             : 
     333       18990 : uint32_t cli_state_get_tid(struct cli_state *cli)
     334             : {
     335       18990 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     336       16449 :                 return smb2cli_tcon_current_id(cli->smb2.tcon);
     337             :         } else {
     338        2541 :                 return (uint32_t)smb1cli_tcon_current_id(cli->smb1.tcon);
     339             :         }
     340             : }
     341             : 
     342          54 : uint32_t cli_state_set_tid(struct cli_state *cli, uint32_t tid)
     343             : {
     344             :         uint32_t ret;
     345          54 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     346           0 :                 ret = smb2cli_tcon_current_id(cli->smb2.tcon);
     347           0 :                 smb2cli_tcon_set_id(cli->smb2.tcon, tid);
     348             :         } else {
     349          54 :                 ret = smb1cli_tcon_current_id(cli->smb1.tcon);
     350          54 :                 smb1cli_tcon_set_id(cli->smb1.tcon, tid);
     351             :         }
     352          54 :         return ret;
     353             : }
     354             : 
     355        8156 : struct smbXcli_tcon *cli_state_save_tcon(struct cli_state *cli)
     356             : {
     357             :         /*
     358             :          * Note. This used to make a deep copy of either
     359             :          * cli->smb2.tcon or cli->smb1.tcon, but this leaves
     360             :          * the original pointer in place which will then get
     361             :          * TALLOC_FREE()'d when the new connection is made on
     362             :          * this cli_state.
     363             :          *
     364             :          * As there may be pipes open on the old connection with
     365             :          * talloc'ed state allocated using the tcon pointer as a
     366             :          * parent we can't deep copy and then free this as that
     367             :          * closes the open pipes.
     368             :          *
     369             :          * This call is used to temporarily swap out a tcon pointer
     370             :          * to allow a new tcon on the same cli_state.
     371             :          *
     372             :          * Just return the raw pointer and set the old value to NULL.
     373             :          * We know we MUST be calling cli_state_restore_tcon() below
     374             :          * to restore before closing the session.
     375             :          *
     376             :          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=13992
     377             :          */
     378        8156 :         struct smbXcli_tcon *tcon_ret = NULL;
     379             : 
     380        8156 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     381        8031 :                 tcon_ret = cli->smb2.tcon;
     382        8031 :                 cli->smb2.tcon = NULL; /* *Not* TALLOC_FREE(). */
     383             :         } else {
     384         125 :                 tcon_ret = cli->smb1.tcon;
     385         125 :                 cli->smb1.tcon = NULL; /* *Not* TALLOC_FREE(). */
     386             :         }
     387        8156 :         return tcon_ret;
     388             : }
     389             : 
     390       16684 : void cli_state_restore_tcon(struct cli_state *cli, struct smbXcli_tcon *tcon)
     391             : {
     392       16684 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     393       14236 :                 TALLOC_FREE(cli->smb2.tcon);
     394       14236 :                 cli->smb2.tcon = tcon;
     395             :         } else {
     396        2448 :                 TALLOC_FREE(cli->smb1.tcon);
     397        2448 :                 cli->smb1.tcon = tcon;
     398             :         }
     399       16684 : }
     400             : 
     401          34 : uint16_t cli_state_get_uid(struct cli_state *cli)
     402             : {
     403          34 :         return smb1cli_session_current_id(cli->smb1.session);
     404             : }
     405             : 
     406         806 : uint16_t cli_state_set_uid(struct cli_state *cli, uint16_t uid)
     407             : {
     408         806 :         uint16_t ret = smb1cli_session_current_id(cli->smb1.session);
     409         806 :         smb1cli_session_set_id(cli->smb1.session, uid);
     410         806 :         return ret;
     411             : }
     412             : 
     413             : /****************************************************************************
     414             :  Set the case sensitivity flag on the packets. Returns old state.
     415             : ****************************************************************************/
     416             : 
     417           0 : bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive)
     418             : {
     419             :         bool ret;
     420             :         uint32_t fs_attrs;
     421             :         struct smbXcli_tcon *tcon;
     422             : 
     423           0 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     424           0 :                 tcon = cli->smb2.tcon;
     425             :         } else {
     426           0 :                 tcon = cli->smb1.tcon;
     427             :         }
     428             : 
     429           0 :         fs_attrs = smbXcli_tcon_get_fs_attributes(tcon);
     430           0 :         if (fs_attrs & FILE_CASE_SENSITIVE_SEARCH) {
     431           0 :                 ret = true;
     432             :         } else {
     433           0 :                 ret = false;
     434             :         }
     435           0 :         if (case_sensitive) {
     436           0 :                 fs_attrs |= FILE_CASE_SENSITIVE_SEARCH;
     437             :         } else {
     438           0 :                 fs_attrs &= ~FILE_CASE_SENSITIVE_SEARCH;
     439             :         }
     440           0 :         smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
     441             : 
     442           0 :         return ret;
     443             : }
     444             : 
     445       20354 : uint32_t cli_state_available_size(struct cli_state *cli, uint32_t ofs)
     446             : {
     447       20354 :         uint32_t ret = smb1cli_conn_max_xmit(cli->conn);
     448             : 
     449       20354 :         if (ofs >= ret) {
     450           0 :                 return 0;
     451             :         }
     452             : 
     453       20354 :         ret -= ofs;
     454             : 
     455       20354 :         return ret;
     456             : }
     457             : 
     458          12 : time_t cli_state_server_time(struct cli_state *cli)
     459             : {
     460             :         NTTIME nt;
     461             :         time_t t;
     462             : 
     463          12 :         nt = smbXcli_conn_server_system_time(cli->conn);
     464          12 :         t = nt_time_to_unix(nt);
     465             : 
     466          12 :         return t;
     467             : }
     468             : 
     469             : struct cli_echo_state {
     470             :         bool is_smb2;
     471             : };
     472             : 
     473             : static void cli_echo_done(struct tevent_req *subreq);
     474             : 
     475         105 : struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     476             :                                  struct cli_state *cli, uint16_t num_echos,
     477             :                                  DATA_BLOB data)
     478             : {
     479             :         struct tevent_req *req, *subreq;
     480             :         struct cli_echo_state *state;
     481             : 
     482         105 :         req = tevent_req_create(mem_ctx, &state, struct cli_echo_state);
     483         105 :         if (req == NULL) {
     484           0 :                 return NULL;
     485             :         }
     486             : 
     487         105 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     488          92 :                 state->is_smb2 = true;
     489          92 :                 subreq = smb2cli_echo_send(state, ev,
     490             :                                            cli->conn,
     491          92 :                                            cli->timeout);
     492             :         } else {
     493          26 :                 subreq = smb1cli_echo_send(state, ev,
     494             :                                            cli->conn,
     495          13 :                                            cli->timeout,
     496             :                                            num_echos,
     497             :                                            data);
     498             :         }
     499         105 :         if (tevent_req_nomem(subreq, req)) {
     500           0 :                 return tevent_req_post(req, ev);
     501             :         }
     502         105 :         tevent_req_set_callback(subreq, cli_echo_done, req);
     503             : 
     504         105 :         return req;
     505             : }
     506             : 
     507         105 : static void cli_echo_done(struct tevent_req *subreq)
     508             : {
     509         105 :         struct tevent_req *req = tevent_req_callback_data(
     510             :                 subreq, struct tevent_req);
     511         105 :         struct cli_echo_state *state = tevent_req_data(
     512             :                 req, struct cli_echo_state);
     513             :         NTSTATUS status;
     514             : 
     515         105 :         if (state->is_smb2) {
     516          92 :                 status = smb2cli_echo_recv(subreq);
     517             :         } else {
     518          13 :                 status = smb1cli_echo_recv(subreq);
     519             :         }
     520         105 :         TALLOC_FREE(subreq);
     521         105 :         if (!NT_STATUS_IS_OK(status)) {
     522           2 :                 tevent_req_nterror(req, status);
     523           2 :                 return;
     524             :         }
     525             : 
     526         103 :         tevent_req_done(req);
     527             : }
     528             : 
     529             : /**
     530             :  * Get the result out from an echo request
     531             :  * @param[in] req       The async_req from cli_echo_send
     532             :  * @retval Did the server reply correctly?
     533             :  */
     534             : 
     535         105 : NTSTATUS cli_echo_recv(struct tevent_req *req)
     536             : {
     537         105 :         return tevent_req_simple_recv_ntstatus(req);
     538             : }
     539             : 
     540             : /**
     541             :  * @brief Send/Receive SMBEcho requests
     542             :  * @param[in] mem_ctx   The memory context to put the async_req on
     543             :  * @param[in] ev        The event context that will call us back
     544             :  * @param[in] cli       The connection to send the echo to
     545             :  * @param[in] num_echos How many times do we want to get the reply?
     546             :  * @param[in] data      The data we want to get back
     547             :  * @retval Did the server reply correctly?
     548             :  */
     549             : 
     550          52 : NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
     551             : {
     552          52 :         TALLOC_CTX *frame = talloc_stackframe();
     553             :         struct tevent_context *ev;
     554             :         struct tevent_req *req;
     555          52 :         NTSTATUS status = NT_STATUS_OK;
     556             : 
     557          52 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     558             :                 /*
     559             :                  * Can't use sync call while an async call is in flight
     560             :                  */
     561           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     562           0 :                 goto fail;
     563             :         }
     564             : 
     565          52 :         ev = samba_tevent_context_init(frame);
     566          52 :         if (ev == NULL) {
     567           0 :                 status = NT_STATUS_NO_MEMORY;
     568           0 :                 goto fail;
     569             :         }
     570             : 
     571          52 :         req = cli_echo_send(frame, ev, cli, num_echos, data);
     572          52 :         if (req == NULL) {
     573           0 :                 status = NT_STATUS_NO_MEMORY;
     574           0 :                 goto fail;
     575             :         }
     576             : 
     577          52 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     578           0 :                 goto fail;
     579             :         }
     580             : 
     581          52 :         status = cli_echo_recv(req);
     582          52 :  fail:
     583          52 :         TALLOC_FREE(frame);
     584          52 :         return status;
     585             : }
     586             : 
     587      327804 : NTSTATUS cli_smb(TALLOC_CTX *mem_ctx, struct cli_state *cli,
     588             :                  uint8_t smb_command, uint8_t additional_flags,
     589             :                  uint8_t wct, uint16_t *vwv,
     590             :                  uint32_t num_bytes, const uint8_t *bytes,
     591             :                  struct tevent_req **result_parent,
     592             :                  uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
     593             :                  uint32_t *pnum_bytes, uint8_t **pbytes)
     594             : {
     595             :         struct tevent_context *ev;
     596      327804 :         struct tevent_req *req = NULL;
     597      327804 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     598             : 
     599      327804 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     600           0 :                 return NT_STATUS_INVALID_PARAMETER;
     601             :         }
     602      327804 :         ev = samba_tevent_context_init(mem_ctx);
     603      327804 :         if (ev == NULL) {
     604           0 :                 goto fail;
     605             :         }
     606      327804 :         req = cli_smb_send(mem_ctx, ev, cli, smb_command, additional_flags, 0,
     607             :                            wct, vwv, num_bytes, bytes);
     608      327804 :         if (req == NULL) {
     609           0 :                 goto fail;
     610             :         }
     611      327804 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     612           0 :                 goto fail;
     613             :         }
     614      327804 :         status = cli_smb_recv(req, NULL, NULL, min_wct, pwct, pvwv,
     615             :                               pnum_bytes, pbytes);
     616      327804 : fail:
     617      327804 :         TALLOC_FREE(ev);
     618      327804 :         if (NT_STATUS_IS_OK(status) && (result_parent != NULL)) {
     619         109 :                 *result_parent = req;
     620             :         }
     621      327804 :         return status;
     622             : }

Generated by: LCOV version 1.13