LCOV - code coverage report
Current view: top level - source3/libsmb - climessage.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 137 189 72.5 %
Date: 2021-09-23 10:06:22 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    client message handling routines
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "../lib/util/tevent_ntstatus.h"
      22             : #include "async_smb.h"
      23             : #include "libsmb/libsmb.h"
      24             : #include "../libcli/smb/smbXcli_base.h"
      25             : 
      26             : struct cli_message_start_state {
      27             :         uint16_t grp;
      28             : };
      29             : 
      30             : static void cli_message_start_done(struct tevent_req *subreq);
      31             : 
      32          28 : static struct tevent_req *cli_message_start_send(TALLOC_CTX *mem_ctx,
      33             :                                                  struct tevent_context *ev,
      34             :                                                  struct cli_state *cli,
      35             :                                                  const char *host,
      36             :                                                  const char *username)
      37             : {
      38             :         struct tevent_req *req, *subreq;
      39             :         struct cli_message_start_state *state;
      40          28 :         char *htmp = NULL;
      41          28 :         char *utmp = NULL;
      42             :         size_t hlen, ulen;
      43             :         uint8_t *bytes, *p;
      44             : 
      45          28 :         req = tevent_req_create(mem_ctx, &state,
      46             :                                 struct cli_message_start_state);
      47          28 :         if (req == NULL) {
      48           0 :                 return NULL;
      49             :         }
      50             : 
      51          28 :         if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
      52          28 :                                    username, strlen(username)+1,
      53             :                                    &utmp, &ulen)) {
      54           0 :                 goto fail;
      55             :         }
      56          28 :         if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
      57          28 :                                    host, strlen(host)+1,
      58             :                                    &htmp, &hlen)) {
      59           0 :                 goto fail;
      60             :         }
      61             : 
      62          28 :         bytes = talloc_array(state, uint8_t, ulen+hlen+2);
      63          28 :         if (bytes == NULL) {
      64           0 :                 goto fail;
      65             :         }
      66          28 :         p = bytes;
      67             : 
      68          28 :         *p++ = 4;
      69          28 :         memcpy(p, utmp, ulen);
      70          28 :         p += ulen;
      71          28 :         *p++ = 4;
      72          28 :         memcpy(p, htmp, hlen);
      73          28 :         TALLOC_FREE(htmp);
      74          28 :         TALLOC_FREE(utmp);
      75             : 
      76          28 :         subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, 0, NULL,
      77          28 :                               talloc_get_size(bytes), bytes);
      78          28 :         if (tevent_req_nomem(subreq, req)) {
      79           0 :                 return tevent_req_post(req, ev);
      80             :         }
      81          28 :         tevent_req_set_callback(subreq, cli_message_start_done, req);
      82          28 :         return req;
      83           0 : fail:
      84           0 :         TALLOC_FREE(htmp);
      85           0 :         TALLOC_FREE(utmp);
      86           0 :         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
      87           0 :         return tevent_req_post(req, ev);
      88             : }
      89             : 
      90          28 : static void cli_message_start_done(struct tevent_req *subreq)
      91             : {
      92          28 :         struct tevent_req *req = tevent_req_callback_data(
      93             :                 subreq, struct tevent_req);
      94          28 :         struct cli_message_start_state *state = tevent_req_data(
      95             :                 req, struct cli_message_start_state);
      96             :         NTSTATUS status;
      97             :         uint8_t wct;
      98             :         uint16_t *vwv;
      99             : 
     100          28 :         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv,
     101             :                               NULL, NULL);
     102          28 :         TALLOC_FREE(subreq);
     103          28 :         if (!NT_STATUS_IS_OK(status)) {
     104           0 :                 TALLOC_FREE(subreq);
     105           0 :                 tevent_req_nterror(req, status);
     106           0 :                 return;
     107             :         }
     108          28 :         if (wct >= 1) {
     109           0 :                 state->grp = SVAL(vwv+0, 0);
     110             :         } else {
     111          28 :                 state->grp = 0;
     112             :         }
     113          28 :         tevent_req_done(req);
     114             : }
     115             : 
     116          28 : static NTSTATUS cli_message_start_recv(struct tevent_req *req,
     117             :                                        uint16_t *pgrp)
     118             : {
     119          28 :         struct cli_message_start_state *state = tevent_req_data(
     120             :                 req, struct cli_message_start_state);
     121             :         NTSTATUS status;
     122             : 
     123          28 :         if (tevent_req_is_nterror(req, &status)) {
     124           0 :                 return status;
     125             :         }
     126          28 :         *pgrp = state->grp;
     127          28 :         return NT_STATUS_OK;
     128             : }
     129             : 
     130             : struct cli_message_text_state {
     131             :         uint16_t vwv;
     132             : };
     133             : 
     134             : static void cli_message_text_done(struct tevent_req *subreq);
     135             : 
     136          28 : static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
     137             :                                                 struct tevent_context *ev,
     138             :                                                 struct cli_state *cli,
     139             :                                                 uint16_t grp,
     140             :                                                 const char *msg,
     141             :                                                 int msglen)
     142             : {
     143             :         struct tevent_req *req, *subreq;
     144             :         struct cli_message_text_state *state;
     145             :         char *tmp;
     146             :         size_t tmplen;
     147             :         uint8_t *bytes;
     148             : 
     149          28 :         req = tevent_req_create(mem_ctx, &state,
     150             :                                 struct cli_message_text_state);
     151          28 :         if (req == NULL) {
     152           0 :                 return NULL;
     153             :         }
     154             : 
     155          28 :         SSVAL(&state->vwv, 0, grp);
     156             : 
     157          28 :         if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
     158             :                                   &tmp, &tmplen)) {
     159          28 :                 msg = tmp;
     160          28 :                 msglen = tmplen;
     161             :         } else {
     162           0 :                 DEBUG(3, ("Conversion failed, sending message in UNIX "
     163             :                           "charset\n"));
     164           0 :                 tmp = NULL;
     165             :         }
     166             : 
     167          28 :         bytes = talloc_array(state, uint8_t, msglen+3);
     168          28 :         if (tevent_req_nomem(bytes, req)) {
     169           0 :                 TALLOC_FREE(tmp);
     170           0 :                 return tevent_req_post(req, ev);
     171             :         }
     172          28 :         SCVAL(bytes, 0, 1);     /* pad */
     173          28 :         SSVAL(bytes+1, 0, msglen);
     174          28 :         memcpy(bytes+3, msg, msglen);
     175          28 :         TALLOC_FREE(tmp);
     176             : 
     177          28 :         subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 0, 1, &state->vwv,
     178          28 :                               talloc_get_size(bytes), bytes);
     179          28 :         if (tevent_req_nomem(subreq, req)) {
     180           0 :                 return tevent_req_post(req, ev);
     181             :         }
     182          28 :         tevent_req_set_callback(subreq, cli_message_text_done, req);
     183          28 :         return req;
     184             : }
     185             : 
     186          28 : static void cli_message_text_done(struct tevent_req *subreq)
     187             : {
     188          28 :         struct tevent_req *req = tevent_req_callback_data(
     189             :                 subreq, struct tevent_req);
     190             :         NTSTATUS status;
     191             : 
     192          28 :         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
     193          28 :         TALLOC_FREE(subreq);
     194          28 :         if (!NT_STATUS_IS_OK(status)) {
     195           0 :                 tevent_req_nterror(req, status);
     196           0 :                 return;
     197             :         }
     198          28 :         tevent_req_done(req);
     199             : }
     200             : 
     201          28 : static NTSTATUS cli_message_text_recv(struct tevent_req *req)
     202             : {
     203          28 :         return tevent_req_simple_recv_ntstatus(req);
     204             : }
     205             : 
     206             : struct cli_message_end_state {
     207             :         uint16_t vwv;
     208             : };
     209             : 
     210             : static void cli_message_end_done(struct tevent_req *subreq);
     211             : 
     212          28 : static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
     213             :                                                 struct tevent_context *ev,
     214             :                                                 struct cli_state *cli,
     215             :                                                 uint16_t grp)
     216             : {
     217             :         struct tevent_req *req, *subreq;
     218             :         struct cli_message_end_state *state;
     219             : 
     220          28 :         req = tevent_req_create(mem_ctx, &state,
     221             :                                 struct cli_message_end_state);
     222          28 :         if (req == NULL) {
     223           0 :                 return NULL;
     224             :         }
     225             : 
     226          28 :         SSVAL(&state->vwv, 0, grp);
     227             : 
     228          28 :         subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 0, 1, &state->vwv,
     229             :                               0, NULL);
     230          28 :         if (tevent_req_nomem(subreq, req)) {
     231           0 :                 return tevent_req_post(req, ev);
     232             :         }
     233          28 :         tevent_req_set_callback(subreq, cli_message_end_done, req);
     234          28 :         return req;
     235             : }
     236             : 
     237          28 : static void cli_message_end_done(struct tevent_req *subreq)
     238             : {
     239          28 :         struct tevent_req *req = tevent_req_callback_data(
     240             :                 subreq, struct tevent_req);
     241             :         NTSTATUS status;
     242             : 
     243          28 :         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
     244          28 :         TALLOC_FREE(subreq);
     245          28 :         if (!NT_STATUS_IS_OK(status)) {
     246           0 :                 tevent_req_nterror(req, status);
     247           0 :                 return;
     248             :         }
     249          28 :         tevent_req_done(req);
     250             : }
     251             : 
     252          28 : static NTSTATUS cli_message_end_recv(struct tevent_req *req)
     253             : {
     254          28 :         return tevent_req_simple_recv_ntstatus(req);
     255             : }
     256             : 
     257             : struct cli_message_state {
     258             :         struct tevent_context *ev;
     259             :         struct cli_state *cli;
     260             :         size_t sent;
     261             :         const char *message;
     262             :         uint16_t grp;
     263             : };
     264             : 
     265             : static void cli_message_started(struct tevent_req *subreq);
     266             : static void cli_message_sent(struct tevent_req *subreq);
     267             : static void cli_message_done(struct tevent_req *subreq);
     268             : 
     269          28 : struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
     270             :                                     struct tevent_context *ev,
     271             :                                     struct cli_state *cli,
     272             :                                     const char *host, const char *username,
     273             :                                     const char *message)
     274             : {
     275             :         struct tevent_req *req, *subreq;
     276             :         struct cli_message_state *state;
     277             : 
     278          28 :         req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
     279          28 :         if (req == NULL) {
     280           0 :                 return NULL;
     281             :         }
     282          28 :         state->ev = ev;
     283          28 :         state->cli = cli;
     284          28 :         state->sent = 0;
     285          28 :         state->message = message;
     286             : 
     287          28 :         subreq = cli_message_start_send(state, ev, cli, host, username);
     288          28 :         if (tevent_req_nomem(subreq, req)) {
     289           0 :                 return tevent_req_post(req, ev);
     290             :         }
     291          28 :         tevent_req_set_callback(subreq, cli_message_started, req);
     292          28 :         return req;
     293             : }
     294             : 
     295          28 : static void cli_message_started(struct tevent_req *subreq)
     296             : {
     297          28 :         struct tevent_req *req = tevent_req_callback_data(
     298             :                 subreq, struct tevent_req);
     299          28 :         struct cli_message_state *state = tevent_req_data(
     300             :                 req, struct cli_message_state);
     301             :         NTSTATUS status;
     302             :         size_t thistime;
     303             : 
     304          28 :         status = cli_message_start_recv(subreq, &state->grp);
     305          28 :         TALLOC_FREE(subreq);
     306          28 :         if (!NT_STATUS_IS_OK(status)) {
     307           0 :                 tevent_req_nterror(req, status);
     308           0 :                 return;
     309             :         }
     310             : 
     311          28 :         thistime = MIN(127, strlen(state->message));
     312             : 
     313          52 :         subreq = cli_message_text_send(state, state->ev, state->cli,
     314          28 :                                        state->grp, state->message, thistime);
     315          28 :         if (tevent_req_nomem(subreq, req)) {
     316           0 :                 return;
     317             :         }
     318          28 :         state->sent += thistime;
     319          28 :         tevent_req_set_callback(subreq, cli_message_sent, req);
     320             : }
     321             : 
     322          28 : static void cli_message_sent(struct tevent_req *subreq)
     323             : {
     324          28 :         struct tevent_req *req = tevent_req_callback_data(
     325             :                 subreq, struct tevent_req);
     326          28 :         struct cli_message_state *state = tevent_req_data(
     327             :                 req, struct cli_message_state);
     328             :         NTSTATUS status;
     329             :         size_t left, thistime;
     330             : 
     331          28 :         status = cli_message_text_recv(subreq);
     332          28 :         TALLOC_FREE(subreq);
     333          28 :         if (!NT_STATUS_IS_OK(status)) {
     334           0 :                 tevent_req_nterror(req, status);
     335           4 :                 return;
     336             :         }
     337             : 
     338          28 :         if (state->sent >= strlen(state->message)) {
     339          28 :                 subreq = cli_message_end_send(state, state->ev, state->cli,
     340          28 :                                               state->grp);
     341          28 :                 if (tevent_req_nomem(subreq, req)) {
     342           0 :                         return;
     343             :                 }
     344          28 :                 tevent_req_set_callback(subreq, cli_message_done, req);
     345          28 :                 return;
     346             :         }
     347             : 
     348           0 :         left = strlen(state->message) - state->sent;
     349           0 :         thistime = MIN(127, left);
     350             : 
     351           0 :         subreq = cli_message_text_send(state, state->ev, state->cli,
     352           0 :                                        state->grp,
     353           0 :                                        state->message + state->sent,
     354             :                                        thistime);
     355           0 :         if (tevent_req_nomem(subreq, req)) {
     356           0 :                 return;
     357             :         }
     358           0 :         state->sent += thistime;
     359           0 :         tevent_req_set_callback(subreq, cli_message_sent, req);
     360             : }
     361             : 
     362          28 : static void cli_message_done(struct tevent_req *subreq)
     363             : {
     364          28 :         struct tevent_req *req = tevent_req_callback_data(
     365             :                 subreq, struct tevent_req);
     366             :         NTSTATUS status;
     367             : 
     368          28 :         status = cli_message_end_recv(subreq);
     369          28 :         TALLOC_FREE(subreq);
     370          28 :         if (!NT_STATUS_IS_OK(status)) {
     371           0 :                 tevent_req_nterror(req, status);
     372           0 :                 return;
     373             :         }
     374          28 :         tevent_req_done(req);
     375             : }
     376             : 
     377          28 : NTSTATUS cli_message_recv(struct tevent_req *req)
     378             : {
     379          28 :         return tevent_req_simple_recv_ntstatus(req);
     380             : }
     381             : 
     382          28 : NTSTATUS cli_message(struct cli_state *cli, const char *host,
     383             :                      const char *username, const char *message)
     384             : {
     385          28 :         TALLOC_CTX *frame = talloc_stackframe();
     386             :         struct tevent_context *ev;
     387             :         struct tevent_req *req;
     388          28 :         NTSTATUS status = NT_STATUS_OK;
     389             : 
     390          28 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     391             :                 /*
     392             :                  * Can't use sync call while an async call is in flight
     393             :                  */
     394           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     395           0 :                 goto fail;
     396             :         }
     397             : 
     398          28 :         ev = samba_tevent_context_init(frame);
     399          28 :         if (ev == NULL) {
     400           0 :                 status = NT_STATUS_NO_MEMORY;
     401           0 :                 goto fail;
     402             :         }
     403             : 
     404          28 :         req = cli_message_send(frame, ev, cli, host, username, message);
     405          28 :         if (req == NULL) {
     406           0 :                 status = NT_STATUS_NO_MEMORY;
     407           0 :                 goto fail;
     408             :         }
     409             : 
     410          28 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     411           0 :                 goto fail;
     412             :         }
     413             : 
     414          28 :         status = cli_message_recv(req);
     415          28 :  fail:
     416          28 :         TALLOC_FREE(frame);
     417          28 :         return status;
     418             : }

Generated by: LCOV version 1.13