mirror of
https://github.com/samba-team/samba.git
synced 2025-08-26 01:49:31 +03:00
s3:libsmb: add basic smb2 client infrastructure
Based on the initial patch from Volker Lendecke <vl@samba.org>. metze
This commit is contained in:
@ -600,6 +600,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
|
||||
libsmb/clioplock.o libsmb/clirap2.o \
|
||||
libsmb/smb_seal.o libsmb/async_smb.o \
|
||||
libsmb/read_smb.o \
|
||||
libsmb/smb2cli_base.o \
|
||||
libsmb/cli_np_tstream.o \
|
||||
libsmb/smbsock_connect.o \
|
||||
$(LIBSAMBA_OBJ) \
|
||||
|
@ -139,6 +139,13 @@ struct cli_state {
|
||||
|
||||
struct tevent_queue *outgoing;
|
||||
struct tevent_req **pending;
|
||||
|
||||
struct {
|
||||
uint64_t mid;
|
||||
uint32_t pid;
|
||||
uint32_t tid;
|
||||
uint64_t uid;
|
||||
} smb2;
|
||||
};
|
||||
|
||||
struct file_info {
|
||||
|
531
source3/libsmb/smb2cli_base.c
Normal file
531
source3/libsmb/smb2cli_base.c
Normal file
@ -0,0 +1,531 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
smb2 lib
|
||||
Copyright (C) Volker Lendecke 2011
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "client.h"
|
||||
#include "read_smb.h"
|
||||
#include "smb2cli_base.h"
|
||||
#include "lib/async_req/async_sock.h"
|
||||
#include "lib/util/tevent_ntstatus.h"
|
||||
|
||||
struct smb2cli_req_state {
|
||||
struct tevent_context *ev;
|
||||
struct cli_state *cli;
|
||||
|
||||
const uint8_t *fixed;
|
||||
uint16_t fixed_len;
|
||||
const uint8_t *dyn;
|
||||
uint16_t dyn_len;
|
||||
|
||||
uint8_t nbt[4];
|
||||
uint8_t hdr[64];
|
||||
uint8_t pad[7]; /* padding space for compounding */
|
||||
|
||||
uint8_t *inbuf;
|
||||
struct iovec *recv_iov;
|
||||
};
|
||||
|
||||
static void smb2cli_req_unset_pending(struct tevent_req *req)
|
||||
{
|
||||
struct smb2cli_req_state *state =
|
||||
tevent_req_data(req,
|
||||
struct smb2cli_req_state);
|
||||
struct cli_state *cli = state->cli;
|
||||
int num_pending = talloc_array_length(cli->pending);
|
||||
int i;
|
||||
|
||||
if (num_pending == 1) {
|
||||
/*
|
||||
* The pending read_smb tevent_req is a child of
|
||||
* cli->pending. So if nothing is pending anymore, we need to
|
||||
* delete the socket read fde.
|
||||
*/
|
||||
TALLOC_FREE(cli->pending);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0; i<num_pending; i++) {
|
||||
if (req == cli->pending[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == num_pending) {
|
||||
/*
|
||||
* Something's seriously broken. Just returning here is the
|
||||
* right thing nevertheless, the point of this routine is to
|
||||
* remove ourselves from cli->pending.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove ourselves from the cli->pending array
|
||||
*/
|
||||
if (num_pending > 1) {
|
||||
cli->pending[i] = cli->pending[num_pending-1];
|
||||
}
|
||||
|
||||
/*
|
||||
* No NULL check here, we're shrinking by sizeof(void *), and
|
||||
* talloc_realloc just adjusts the size for this.
|
||||
*/
|
||||
cli->pending = talloc_realloc(NULL, cli->pending, struct tevent_req *,
|
||||
num_pending - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
static int smb2cli_req_destructor(struct tevent_req *req)
|
||||
{
|
||||
smb2cli_req_unset_pending(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smb2cli_inbuf_received(struct tevent_req *subreq);
|
||||
|
||||
static bool smb2cli_req_set_pending(struct tevent_req *req)
|
||||
{
|
||||
struct smb2cli_req_state *state =
|
||||
tevent_req_data(req,
|
||||
struct smb2cli_req_state);
|
||||
struct cli_state *cli;
|
||||
struct tevent_req **pending;
|
||||
int num_pending;
|
||||
struct tevent_req *subreq;
|
||||
|
||||
cli = state->cli;
|
||||
num_pending = talloc_array_length(cli->pending);
|
||||
|
||||
pending = talloc_realloc(cli, cli->pending, struct tevent_req *,
|
||||
num_pending+1);
|
||||
if (pending == NULL) {
|
||||
return false;
|
||||
}
|
||||
pending[num_pending] = req;
|
||||
cli->pending = pending;
|
||||
talloc_set_destructor(req, smb2cli_req_destructor);
|
||||
|
||||
if (num_pending > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're the first ones, add the read_smb request that waits for the
|
||||
* answer from the server
|
||||
*/
|
||||
subreq = read_smb_send(cli->pending, state->ev, cli->fd);
|
||||
if (subreq == NULL) {
|
||||
smb2cli_req_unset_pending(req);
|
||||
return false;
|
||||
}
|
||||
tevent_req_set_callback(subreq, smb2cli_inbuf_received, cli);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct cli_state *cli,
|
||||
uint16_t cmd,
|
||||
uint32_t flags,
|
||||
const uint8_t *fixed,
|
||||
uint16_t fixed_len,
|
||||
const uint8_t *dyn,
|
||||
uint16_t dyn_len)
|
||||
{
|
||||
struct tevent_req *result;
|
||||
struct smb2cli_req_state *state;
|
||||
|
||||
result = tevent_req_create(mem_ctx, &state,
|
||||
struct smb2cli_req_state);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
state->ev = ev;
|
||||
state->cli = cli;
|
||||
|
||||
state->fixed = fixed;
|
||||
state->fixed_len = fixed_len;
|
||||
state->dyn = dyn;
|
||||
state->dyn_len = dyn_len;
|
||||
|
||||
SIVAL(state->hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
|
||||
SSVAL(state->hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
|
||||
SSVAL(state->hdr, SMB2_HDR_EPOCH, 1);
|
||||
SIVAL(state->hdr, SMB2_HDR_STATUS, NT_STATUS_V(NT_STATUS_OK));
|
||||
SSVAL(state->hdr, SMB2_HDR_OPCODE, cmd);
|
||||
SSVAL(state->hdr, SMB2_HDR_CREDIT, 31);
|
||||
SIVAL(state->hdr, SMB2_HDR_FLAGS, flags);
|
||||
SIVAL(state->hdr, SMB2_HDR_PID, cli->smb2.pid);
|
||||
SIVAL(state->hdr, SMB2_HDR_TID, cli->smb2.tid);
|
||||
SBVAL(state->hdr, SMB2_HDR_SESSION_ID, cli->smb2.uid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void smb2cli_writev_done(struct tevent_req *subreq);
|
||||
|
||||
NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
|
||||
int num_reqs)
|
||||
{
|
||||
struct smb2cli_req_state *state;
|
||||
struct tevent_req *subreq;
|
||||
struct iovec *iov;
|
||||
int i, num_iov, nbt_len;
|
||||
|
||||
/*
|
||||
* 1 for the nbt length
|
||||
* per request: HDR, fixed, dyn, padding
|
||||
* -1 because the last one does not need padding
|
||||
*/
|
||||
|
||||
iov = talloc_array(reqs[0], struct iovec, 1 + 4*num_reqs - 1);
|
||||
if (iov == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
num_iov = 1;
|
||||
nbt_len = 0;
|
||||
|
||||
for (i=0; i<num_reqs; i++) {
|
||||
size_t reqlen;
|
||||
bool ret;
|
||||
|
||||
state = tevent_req_data(reqs[i], struct smb2cli_req_state);
|
||||
|
||||
SBVAL(state->hdr, SMB2_HDR_MESSAGE_ID, state->cli->smb2.mid++);
|
||||
|
||||
iov[num_iov].iov_base = state->hdr;
|
||||
iov[num_iov].iov_len = sizeof(state->hdr);
|
||||
num_iov += 1;
|
||||
|
||||
iov[num_iov].iov_base = discard_const(state->fixed);
|
||||
iov[num_iov].iov_len = state->fixed_len;
|
||||
num_iov += 1;
|
||||
|
||||
if (state->dyn != NULL) {
|
||||
iov[num_iov].iov_base = discard_const(state->dyn);
|
||||
iov[num_iov].iov_len = state->dyn_len;
|
||||
num_iov += 1;
|
||||
}
|
||||
|
||||
reqlen = sizeof(state->hdr) + state->fixed_len +
|
||||
state->dyn_len;
|
||||
|
||||
if (i < num_reqs-1) {
|
||||
if ((reqlen % 8) > 0) {
|
||||
uint8_t pad = 8 - (reqlen % 8);
|
||||
iov[num_iov].iov_base = state->pad;
|
||||
iov[num_iov].iov_len = pad;
|
||||
num_iov += 1;
|
||||
reqlen += pad;
|
||||
}
|
||||
SIVAL(state->hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
|
||||
}
|
||||
nbt_len += reqlen;
|
||||
|
||||
ret = smb2cli_req_set_pending(reqs[i]);
|
||||
if (!ret) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Do signing here
|
||||
*/
|
||||
|
||||
state = tevent_req_data(reqs[0], struct smb2cli_req_state);
|
||||
_smb_setlen_large(state->nbt, nbt_len);
|
||||
iov[0].iov_base = state->nbt;
|
||||
iov[0].iov_len = sizeof(state->nbt);
|
||||
|
||||
subreq = writev_send(state, state->ev, state->cli->outgoing,
|
||||
state->cli->fd, false, iov, num_iov);
|
||||
if (subreq == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
tevent_req_set_callback(subreq, smb2cli_writev_done, reqs[0]);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct cli_state *cli,
|
||||
uint16_t cmd,
|
||||
uint32_t flags,
|
||||
const uint8_t *fixed,
|
||||
uint16_t fixed_len,
|
||||
const uint8_t *dyn,
|
||||
uint16_t dyn_len)
|
||||
{
|
||||
struct tevent_req *req;
|
||||
NTSTATUS status;
|
||||
|
||||
req = smb2cli_req_create(mem_ctx, ev, cli, cmd, flags,
|
||||
fixed, fixed_len, dyn, dyn_len);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
return req;
|
||||
}
|
||||
status = smb2cli_req_compound_submit(&req, 1);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
static void smb2cli_writev_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req =
|
||||
tevent_req_callback_data(subreq,
|
||||
struct tevent_req);
|
||||
struct smb2cli_req_state *state =
|
||||
tevent_req_data(req,
|
||||
struct smb2cli_req_state);
|
||||
ssize_t nwritten;
|
||||
int err;
|
||||
|
||||
nwritten = writev_recv(subreq, &err);
|
||||
TALLOC_FREE(subreq);
|
||||
if (nwritten == -1) {
|
||||
if (state->cli->fd != -1) {
|
||||
close(state->cli->fd);
|
||||
state->cli->fd = -1;
|
||||
}
|
||||
tevent_req_nterror(req, map_nt_error_from_unix(err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS smb2cli_inbuf_parse_compound(uint8_t *buf, TALLOC_CTX *mem_ctx,
|
||||
struct iovec **piov, int *pnum_iov)
|
||||
{
|
||||
struct iovec *iov;
|
||||
int num_iov;
|
||||
size_t buflen;
|
||||
size_t taken;
|
||||
|
||||
num_iov = 1;
|
||||
|
||||
iov = talloc_array(mem_ctx, struct iovec, num_iov);
|
||||
if (iov == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = 4;
|
||||
|
||||
buflen = smb_len_large(buf) + 4;
|
||||
taken = 4;
|
||||
|
||||
while (taken < buflen) {
|
||||
size_t len = buflen - taken;
|
||||
uint8_t *hdr = buf + taken;
|
||||
struct iovec *cur;
|
||||
size_t full_size;
|
||||
size_t next_command_ofs;
|
||||
uint16_t body_size;
|
||||
struct iovec *iov_tmp;
|
||||
|
||||
/*
|
||||
* We need the header plus the body length field
|
||||
*/
|
||||
|
||||
if (len < SMB2_HDR_BODY + 2) {
|
||||
DEBUG(10, ("%d bytes left, expected at least %d\n",
|
||||
(int)len, SMB2_HDR_BODY));
|
||||
goto inval;
|
||||
}
|
||||
if (IVAL(hdr, 0) != SMB2_MAGIC) {
|
||||
DEBUG(10, ("Got non-SMB2 PDU: %x\n",
|
||||
IVAL(hdr, 0)));
|
||||
goto inval;
|
||||
}
|
||||
if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
|
||||
DEBUG(10, ("Got HDR len %d, expected %d\n",
|
||||
SVAL(hdr, 4), SMB2_HDR_BODY));
|
||||
goto inval;
|
||||
}
|
||||
|
||||
full_size = len;
|
||||
next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
|
||||
body_size = SVAL(hdr, SMB2_HDR_BODY);
|
||||
|
||||
if (next_command_ofs != 0) {
|
||||
if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
|
||||
goto inval;
|
||||
}
|
||||
if (next_command_ofs > full_size) {
|
||||
goto inval;
|
||||
}
|
||||
full_size = next_command_ofs;
|
||||
}
|
||||
if (body_size < 2) {
|
||||
goto inval;
|
||||
}
|
||||
body_size &= 0xfffe;
|
||||
|
||||
if (body_size > (full_size - SMB2_HDR_BODY)) {
|
||||
goto inval;
|
||||
}
|
||||
|
||||
iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
|
||||
num_iov + 3);
|
||||
if (iov_tmp == NULL) {
|
||||
TALLOC_FREE(iov);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
iov = iov_tmp;
|
||||
cur = &iov[num_iov];
|
||||
num_iov += 3;
|
||||
|
||||
cur[0].iov_base = hdr;
|
||||
cur[0].iov_len = SMB2_HDR_BODY;
|
||||
cur[1].iov_base = hdr + SMB2_HDR_BODY;
|
||||
cur[1].iov_len = body_size;
|
||||
cur[2].iov_base = hdr + SMB2_HDR_BODY + body_size;
|
||||
cur[2].iov_len = full_size - (SMB2_HDR_BODY + body_size);
|
||||
|
||||
taken += full_size;
|
||||
}
|
||||
|
||||
*piov = iov;
|
||||
*pnum_iov = num_iov;
|
||||
return NT_STATUS_OK;
|
||||
|
||||
inval:
|
||||
TALLOC_FREE(iov);
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
|
||||
static struct tevent_req *cli_smb2_find_pending(struct cli_state *cli,
|
||||
uint64_t mid)
|
||||
{
|
||||
int num_pending = talloc_array_length(cli->pending);
|
||||
int i;
|
||||
|
||||
for (i=0; i<num_pending; i++) {
|
||||
struct tevent_req *req = cli->pending[i];
|
||||
struct smb2cli_req_state *state =
|
||||
tevent_req_data(req,
|
||||
struct smb2cli_req_state);
|
||||
|
||||
if (mid == BVAL(state->hdr, SMB2_HDR_MESSAGE_ID)) {
|
||||
return req;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void smb2cli_inbuf_received(struct tevent_req *subreq)
|
||||
{
|
||||
struct cli_state *cli =
|
||||
tevent_req_callback_data(subreq,
|
||||
struct cli_state);
|
||||
struct tevent_req *req;
|
||||
struct iovec *iov;
|
||||
int i, num_iov;
|
||||
NTSTATUS status;
|
||||
uint8_t *inbuf;
|
||||
ssize_t received;
|
||||
int err;
|
||||
|
||||
received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err);
|
||||
TALLOC_FREE(subreq);
|
||||
if (received == -1) {
|
||||
if (cli->fd != -1) {
|
||||
close(cli->fd);
|
||||
cli->fd = -1;
|
||||
}
|
||||
status = map_nt_error_from_unix(err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = smb2cli_inbuf_parse_compound(inbuf, talloc_tos(),
|
||||
&iov, &num_iov);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i=1; i<num_iov; i+=3) {
|
||||
struct iovec *cur = &iov[i];
|
||||
uint8_t *inhdr = (uint8_t *)cur[0].iov_base;
|
||||
struct smb2cli_req_state *state;
|
||||
|
||||
req = cli_smb2_find_pending(
|
||||
cli, BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
|
||||
if (req == NULL) {
|
||||
/*
|
||||
* oplock breaks ??
|
||||
*/
|
||||
goto fail;
|
||||
}
|
||||
state = tevent_req_data(req, struct smb2cli_req_state);
|
||||
if (i+3 >= num_iov) {
|
||||
/* last in chain */
|
||||
state->inbuf = inbuf;
|
||||
}
|
||||
state->recv_iov = cur;
|
||||
tevent_req_done(req);
|
||||
}
|
||||
return;
|
||||
fail:
|
||||
/*
|
||||
* Cancel all pending requests. We don't do a for-loop walking
|
||||
* cli->pending because that array changes in
|
||||
* cli_smb_req_destructor().
|
||||
*/
|
||||
while (talloc_array_length(cli->pending) > 0) {
|
||||
req = cli->pending[0];
|
||||
talloc_set_destructor(req, NULL);
|
||||
smb2cli_req_destructor(req);
|
||||
tevent_req_nterror(req, status);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
||||
struct iovec **piov, int body_size)
|
||||
{
|
||||
struct smb2cli_req_state *state =
|
||||
tevent_req_data(req,
|
||||
struct smb2cli_req_state);
|
||||
NTSTATUS status;
|
||||
|
||||
if (tevent_req_is_nterror(req, &status)) {
|
||||
return status;
|
||||
}
|
||||
if (body_size != 0) {
|
||||
if (body_size != SVAL(state->recv_iov[1].iov_base, 0)) {
|
||||
return NT_STATUS_INVALID_NETWORK_RESPONSE;
|
||||
}
|
||||
}
|
||||
talloc_steal(req, state->inbuf);
|
||||
if (piov != NULL) {
|
||||
*piov = state->recv_iov;
|
||||
}
|
||||
|
||||
return NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
|
||||
}
|
||||
|
||||
uint8_t *smb2cli_req_inbuf(struct tevent_req *req)
|
||||
{
|
||||
struct smb2cli_req_state *state = tevent_req_data(
|
||||
req, struct smb2cli_req_state);
|
||||
|
||||
return state->inbuf;
|
||||
}
|
47
source3/libsmb/smb2cli_base.h
Normal file
47
source3/libsmb/smb2cli_base.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
smb2 client routines
|
||||
Copyright (C) Volker Lendecke 2011
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SMB2CLI_BASE_H__
|
||||
#define __SMB2CLI_BASE_H__
|
||||
|
||||
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct cli_state *cli,
|
||||
uint16_t cmd,
|
||||
uint32_t flags,
|
||||
const uint8_t *fixed,
|
||||
uint16_t fixed_len,
|
||||
const uint8_t *dyn,
|
||||
uint16_t dyn_len);
|
||||
NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
|
||||
int num_reqs);
|
||||
struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct cli_state *cli,
|
||||
uint16_t cmd,
|
||||
uint32_t flags,
|
||||
const uint8_t *fixed,
|
||||
uint16_t fixed_len,
|
||||
const uint8_t *dyn,
|
||||
uint16_t dyn_len);
|
||||
NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
||||
struct iovec **piov, int body_size);
|
||||
uint8_t *smb2cli_req_inbuf(struct tevent_req *req);
|
||||
|
||||
#endif
|
@ -136,6 +136,7 @@ LIBSMB_SRC = '''libsmb/clientgen.c libsmb/cliconnect.c libsmb/clifile.c
|
||||
libsmb/clistr.c libsmb/cliquota.c libsmb/clifsinfo.c libsmb/clidfs.c
|
||||
libsmb/clioplock.c libsmb/clirap2.c
|
||||
libsmb/smb_seal.c libsmb/async_smb.c libsmb/read_smb.c
|
||||
libsmb/smb2cli_base.c
|
||||
libsmb/cli_np_tstream.c
|
||||
libsmb/reparse_symlink.c
|
||||
libsmb/clisymlink.c
|
||||
|
Reference in New Issue
Block a user