LCOV - code coverage report
Current view: top level - source3/libsmb - climessage.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 140 208 67.3 %
Date: 2024-04-21 15:09:00 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           0 :         struct tevent_req *req, *subreq;
      39           0 :         struct cli_message_start_state *state;
      40          28 :         char *htmp = NULL;
      41          28 :         char *utmp = NULL;
      42           0 :         size_t hlen, ulen;
      43           0 :         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           0 :         NTSTATUS status;
      97           0 :         uint8_t wct;
      98           0 :         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 (tevent_req_nterror(req, status)) {
     104          22 :                 return;
     105             :         }
     106           6 :         if (wct >= 1) {
     107           0 :                 state->grp = SVAL(vwv+0, 0);
     108             :         } else {
     109           6 :                 state->grp = 0;
     110             :         }
     111           6 :         tevent_req_done(req);
     112             : }
     113             : 
     114          28 : static NTSTATUS cli_message_start_recv(struct tevent_req *req,
     115             :                                        uint16_t *pgrp)
     116             : {
     117          28 :         struct cli_message_start_state *state = tevent_req_data(
     118             :                 req, struct cli_message_start_state);
     119           0 :         NTSTATUS status;
     120             : 
     121          28 :         if (tevent_req_is_nterror(req, &status)) {
     122          22 :                 return status;
     123             :         }
     124           6 :         *pgrp = state->grp;
     125           6 :         return NT_STATUS_OK;
     126             : }
     127             : 
     128             : struct cli_message_text_state {
     129             :         uint16_t vwv;
     130             : };
     131             : 
     132             : static void cli_message_text_done(struct tevent_req *subreq);
     133             : 
     134           6 : static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
     135             :                                                 struct tevent_context *ev,
     136             :                                                 struct cli_state *cli,
     137             :                                                 uint16_t grp,
     138             :                                                 const char *msg,
     139             :                                                 int msglen)
     140             : {
     141           0 :         struct tevent_req *req, *subreq;
     142           0 :         struct cli_message_text_state *state;
     143           0 :         char *tmp;
     144           0 :         size_t tmplen;
     145           0 :         uint8_t *bytes;
     146             : 
     147           6 :         req = tevent_req_create(mem_ctx, &state,
     148             :                                 struct cli_message_text_state);
     149           6 :         if (req == NULL) {
     150           0 :                 return NULL;
     151             :         }
     152             : 
     153           6 :         SSVAL(&state->vwv, 0, grp);
     154             : 
     155           6 :         if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
     156             :                                   &tmp, &tmplen)) {
     157           6 :                 msg = tmp;
     158           6 :                 msglen = tmplen;
     159             :         } else {
     160           0 :                 DEBUG(3, ("Conversion failed, sending message in UNIX "
     161             :                           "charset\n"));
     162           0 :                 tmp = NULL;
     163             :         }
     164             : 
     165           6 :         bytes = talloc_array(state, uint8_t, msglen+3);
     166           6 :         if (tevent_req_nomem(bytes, req)) {
     167           0 :                 TALLOC_FREE(tmp);
     168           0 :                 return tevent_req_post(req, ev);
     169             :         }
     170           6 :         SCVAL(bytes, 0, 1);     /* pad */
     171           6 :         SSVAL(bytes+1, 0, msglen);
     172           6 :         memcpy(bytes+3, msg, msglen);
     173           6 :         TALLOC_FREE(tmp);
     174             : 
     175           6 :         subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 0, 1, &state->vwv,
     176           6 :                               talloc_get_size(bytes), bytes);
     177           6 :         if (tevent_req_nomem(subreq, req)) {
     178           0 :                 return tevent_req_post(req, ev);
     179             :         }
     180           6 :         tevent_req_set_callback(subreq, cli_message_text_done, req);
     181           6 :         return req;
     182             : }
     183             : 
     184           6 : static void cli_message_text_done(struct tevent_req *subreq)
     185             : {
     186           6 :         struct tevent_req *req = tevent_req_callback_data(
     187             :                 subreq, struct tevent_req);
     188           0 :         NTSTATUS status;
     189             : 
     190           6 :         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
     191           6 :         TALLOC_FREE(subreq);
     192           6 :         if (tevent_req_nterror(req, status)) {
     193           0 :                 return;
     194             :         }
     195           6 :         tevent_req_done(req);
     196             : }
     197             : 
     198           6 : static NTSTATUS cli_message_text_recv(struct tevent_req *req)
     199             : {
     200           6 :         return tevent_req_simple_recv_ntstatus(req);
     201             : }
     202             : 
     203             : struct cli_message_end_state {
     204             :         uint16_t vwv;
     205             : };
     206             : 
     207             : static void cli_message_end_done(struct tevent_req *subreq);
     208             : 
     209           6 : static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
     210             :                                                 struct tevent_context *ev,
     211             :                                                 struct cli_state *cli,
     212             :                                                 uint16_t grp)
     213             : {
     214           0 :         struct tevent_req *req, *subreq;
     215           0 :         struct cli_message_end_state *state;
     216             : 
     217           6 :         req = tevent_req_create(mem_ctx, &state,
     218             :                                 struct cli_message_end_state);
     219           6 :         if (req == NULL) {
     220           0 :                 return NULL;
     221             :         }
     222             : 
     223           6 :         SSVAL(&state->vwv, 0, grp);
     224             : 
     225           6 :         subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 0, 1, &state->vwv,
     226             :                               0, NULL);
     227           6 :         if (tevent_req_nomem(subreq, req)) {
     228           0 :                 return tevent_req_post(req, ev);
     229             :         }
     230           6 :         tevent_req_set_callback(subreq, cli_message_end_done, req);
     231           6 :         return req;
     232             : }
     233             : 
     234           6 : static void cli_message_end_done(struct tevent_req *subreq)
     235             : {
     236           6 :         struct tevent_req *req = tevent_req_callback_data(
     237             :                 subreq, struct tevent_req);
     238           0 :         NTSTATUS status;
     239             : 
     240           6 :         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
     241           6 :         TALLOC_FREE(subreq);
     242           6 :         if (tevent_req_nterror(req, status)) {
     243           0 :                 return;
     244             :         }
     245           6 :         tevent_req_done(req);
     246             : }
     247             : 
     248           6 : static NTSTATUS cli_message_end_recv(struct tevent_req *req)
     249             : {
     250           6 :         return tevent_req_simple_recv_ntstatus(req);
     251             : }
     252             : 
     253             : struct cli_message_state {
     254             :         struct tevent_context *ev;
     255             :         struct cli_state *cli;
     256             :         size_t sent;
     257             :         const char *message;
     258             :         uint16_t grp;
     259             : };
     260             : 
     261             : static void cli_message_started(struct tevent_req *subreq);
     262             : static void cli_message_sent(struct tevent_req *subreq);
     263             : static void cli_message_done(struct tevent_req *subreq);
     264             : 
     265          28 : struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
     266             :                                     struct tevent_context *ev,
     267             :                                     struct cli_state *cli,
     268             :                                     const char *host, const char *username,
     269             :                                     const char *message)
     270             : {
     271           0 :         struct tevent_req *req, *subreq;
     272           0 :         struct cli_message_state *state;
     273             : 
     274          28 :         req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
     275          28 :         if (req == NULL) {
     276           0 :                 return NULL;
     277             :         }
     278          28 :         state->ev = ev;
     279          28 :         state->cli = cli;
     280          28 :         state->sent = 0;
     281          28 :         state->message = message;
     282             : 
     283          28 :         subreq = cli_message_start_send(state, ev, cli, host, username);
     284          28 :         if (tevent_req_nomem(subreq, req)) {
     285           0 :                 return tevent_req_post(req, ev);
     286             :         }
     287          28 :         tevent_req_set_callback(subreq, cli_message_started, req);
     288          28 :         return req;
     289             : }
     290             : 
     291          28 : static void cli_message_started(struct tevent_req *subreq)
     292             : {
     293          28 :         struct tevent_req *req = tevent_req_callback_data(
     294             :                 subreq, struct tevent_req);
     295          28 :         struct cli_message_state *state = tevent_req_data(
     296             :                 req, struct cli_message_state);
     297           0 :         NTSTATUS status;
     298           0 :         size_t thistime;
     299             : 
     300          28 :         status = cli_message_start_recv(subreq, &state->grp);
     301          28 :         TALLOC_FREE(subreq);
     302          28 :         if (tevent_req_nterror(req, status)) {
     303          22 :                 return;
     304             :         }
     305             : 
     306           6 :         thistime = MIN(127, strlen(state->message));
     307             : 
     308           6 :         subreq = cli_message_text_send(state, state->ev, state->cli,
     309           6 :                                        state->grp, state->message, thistime);
     310           6 :         if (tevent_req_nomem(subreq, req)) {
     311           0 :                 return;
     312             :         }
     313           6 :         state->sent += thistime;
     314           6 :         tevent_req_set_callback(subreq, cli_message_sent, req);
     315             : }
     316             : 
     317           6 : static void cli_message_sent(struct tevent_req *subreq)
     318             : {
     319           6 :         struct tevent_req *req = tevent_req_callback_data(
     320             :                 subreq, struct tevent_req);
     321           6 :         struct cli_message_state *state = tevent_req_data(
     322             :                 req, struct cli_message_state);
     323           0 :         NTSTATUS status;
     324           0 :         size_t left, thistime;
     325             : 
     326           6 :         status = cli_message_text_recv(subreq);
     327           6 :         TALLOC_FREE(subreq);
     328           6 :         if (tevent_req_nterror(req, status)) {
     329           6 :                 return;
     330             :         }
     331             : 
     332           6 :         if (state->sent >= strlen(state->message)) {
     333           6 :                 subreq = cli_message_end_send(state, state->ev, state->cli,
     334           6 :                                               state->grp);
     335           6 :                 if (tevent_req_nomem(subreq, req)) {
     336           0 :                         return;
     337             :                 }
     338           6 :                 tevent_req_set_callback(subreq, cli_message_done, req);
     339           6 :                 return;
     340             :         }
     341             : 
     342           0 :         left = strlen(state->message) - state->sent;
     343           0 :         thistime = MIN(127, left);
     344             : 
     345           0 :         subreq = cli_message_text_send(state, state->ev, state->cli,
     346           0 :                                        state->grp,
     347           0 :                                        state->message + state->sent,
     348             :                                        thistime);
     349           0 :         if (tevent_req_nomem(subreq, req)) {
     350           0 :                 return;
     351             :         }
     352           0 :         state->sent += thistime;
     353           0 :         tevent_req_set_callback(subreq, cli_message_sent, req);
     354             : }
     355             : 
     356           6 : static void cli_message_done(struct tevent_req *subreq)
     357             : {
     358           6 :         struct tevent_req *req = tevent_req_callback_data(
     359             :                 subreq, struct tevent_req);
     360           0 :         NTSTATUS status;
     361             : 
     362           6 :         status = cli_message_end_recv(subreq);
     363           6 :         TALLOC_FREE(subreq);
     364           6 :         if (tevent_req_nterror(req, status)) {
     365           0 :                 return;
     366             :         }
     367           6 :         tevent_req_done(req);
     368             : }
     369             : 
     370          28 : NTSTATUS cli_message_recv(struct tevent_req *req)
     371             : {
     372          28 :         return tevent_req_simple_recv_ntstatus(req);
     373             : }
     374             : 
     375          28 : NTSTATUS cli_message(struct cli_state *cli, const char *host,
     376             :                      const char *username, const char *message)
     377             : {
     378          28 :         TALLOC_CTX *frame = talloc_stackframe();
     379           0 :         struct tevent_context *ev;
     380           0 :         struct tevent_req *req;
     381          28 :         NTSTATUS status = NT_STATUS_OK;
     382             : 
     383          28 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     384             :                 /*
     385             :                  * Can't use sync call while an async call is in flight
     386             :                  */
     387           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     388           0 :                 goto fail;
     389             :         }
     390             : 
     391          28 :         ev = samba_tevent_context_init(frame);
     392          28 :         if (ev == NULL) {
     393           0 :                 status = NT_STATUS_NO_MEMORY;
     394           0 :                 goto fail;
     395             :         }
     396             : 
     397          28 :         req = cli_message_send(frame, ev, cli, host, username, message);
     398          28 :         if (req == NULL) {
     399           0 :                 status = NT_STATUS_NO_MEMORY;
     400           0 :                 goto fail;
     401             :         }
     402             : 
     403          28 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     404           0 :                 goto fail;
     405             :         }
     406             : 
     407          28 :         status = cli_message_recv(req);
     408          28 :  fail:
     409          28 :         TALLOC_FREE(frame);
     410          28 :         return status;
     411             : }

Generated by: LCOV version 1.14