Coverage Report

Created: 2026-02-14 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/libcli/smb/read_smb.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Infrastructure for async SMB client requests
4
   Copyright (C) Volker Lendecke 2008
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 "system/network.h"
22
#include "lib/async_req/async_sock.h"
23
#include "read_smb.h"
24
#include "lib/util/tevent_unix.h"
25
#include "libcli/smb/smb_constants.h"
26
27
/*
28
 * Read an smb packet asynchronously, discard keepalives
29
 */
30
31
struct read_smb_state {
32
  struct tevent_context *ev;
33
  int fd;
34
  uint8_t *buf;
35
};
36
37
static void read_smb_done(struct tevent_req *subreq);
38
39
struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
40
         struct tevent_context *ev,
41
         int fd)
42
0
{
43
0
  struct tevent_req *result, *subreq;
44
0
  struct read_smb_state *state;
45
46
0
  result = tevent_req_create(mem_ctx, &state, struct read_smb_state);
47
0
  if (result == NULL) {
48
0
    return NULL;
49
0
  }
50
0
  state->ev = ev;
51
0
  state->fd = fd;
52
53
0
  subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL);
54
0
  if (subreq == NULL) {
55
0
    goto fail;
56
0
  }
57
0
  tevent_req_set_callback(subreq, read_smb_done, result);
58
0
  return result;
59
0
 fail:
60
0
  TALLOC_FREE(result);
61
0
  return NULL;
62
0
}
63
64
ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data)
65
0
{
66
0
  if (buflen > 4) {
67
0
    return 0; /* We've been here, we're done */
68
0
  }
69
0
  return smb_len_tcp(buf);
70
0
}
71
72
static void read_smb_done(struct tevent_req *subreq)
73
0
{
74
0
  struct tevent_req *req = tevent_req_callback_data(
75
0
    subreq, struct tevent_req);
76
0
  struct read_smb_state *state = tevent_req_data(
77
0
    req, struct read_smb_state);
78
0
  ssize_t len;
79
0
  int err;
80
81
0
  len = read_packet_recv(subreq, state, &state->buf, &err);
82
0
  TALLOC_FREE(subreq);
83
0
  if (len == -1) {
84
0
    tevent_req_error(req, err);
85
0
    return;
86
0
  }
87
88
0
  if (CVAL(state->buf, 0) == NBSSkeepalive) {
89
0
    subreq = read_packet_send(state, state->ev, state->fd, 4,
90
0
            read_smb_more, NULL);
91
0
    if (tevent_req_nomem(subreq, req)) {
92
0
      return;
93
0
    }
94
0
    tevent_req_set_callback(subreq, read_smb_done, req);
95
0
    return;
96
0
  }
97
0
  tevent_req_done(req);
98
0
}
99
100
ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
101
          uint8_t **pbuf, int *perrno)
102
0
{
103
0
  struct read_smb_state *state = tevent_req_data(
104
0
    req, struct read_smb_state);
105
106
0
  if (tevent_req_is_unix_error(req, perrno)) {
107
0
    tevent_req_received(req);
108
0
    return -1;
109
0
  }
110
0
  *pbuf = talloc_move(mem_ctx, &state->buf);
111
0
  tevent_req_received(req);
112
0
  return talloc_get_size(*pbuf);
113
0
}