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

Generated by: LCOV version 1.13