DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
smb_client.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file smb_client.h
6 * @brief SMB2 client dialogue engine (DETWS_ENABLE_SMB) - drives the smb2 / ntlm / spnego wire
7 * codecs through a real session to open a file on a Windows share.
8 *
9 * The wire codecs (smb2.h, ntlm.h, ntlmssp.h, spnego.h) are pure builders/parsers; this ties them
10 * into the actual exchange: NEGOTIATE, the two-round NTLMv2 SESSION_SETUP (SPNEGO-wrapped),
11 * TREE_CONNECT to `\\server\share`, and CREATE to open the file - handing back a handle that
12 * smb_read / smb_write / smb_close use. Like the SMTP engine it is written against a send/recv seam,
13 * so the whole exchange is host-tested with a scripted mock SMB2 server (no lwIP / real share).
14 *
15 * Direct-TCP framing (the 4-byte length prefix) is handled here: each request is framed before
16 * `send`, each response is de-framed after `recv` (accumulating until a full message arrives).
17 *
18 * @author Douglas Quigg (dstroy0)
19 * @date 2026
20 */
21
22#ifndef DETERMINISTICESPASYNCWEBSERVER_SMB_CLIENT_H
23#define DETERMINISTICESPASYNCWEBSERVER_SMB_CLIENT_H
24
25#include "ServerConfig.h"
26
27#if DETWS_ENABLE_SMB
28
29#include <stddef.h>
30#include <stdint.h>
31
32/** @brief Result of an SMB client operation. 0 is success; each failure is a distinct code. */
33enum class SmbResult : int32_t
34{
35 SMB_OK = 0,
36 SMB_ERR_ARG = -1, ///< a required field was null/empty
37 SMB_ERR_IO = -2, ///< a send/recv failed, timed out, or the peer closed mid-message
38 SMB_ERR_PROTOCOL = -3, ///< a malformed response, or an unexpected NT status
39 SMB_ERR_AUTH = -4, ///< SESSION_SETUP was rejected (bad user/password/domain)
40 SMB_ERR_OVERFLOW = -5, ///< a message did not fit the work buffer (DETWS_SMB_BUF)
41};
42
43/**
44 * @brief Transport seam: the engine moves raw bytes only through these, so it runs against a real
45 * socket (det_client) or a test mock.
46 * @return send: bytes written (must equal @p len), else < 0. recv: bytes read (> 0), else <= 0 on
47 * close / error / timeout.
48 */
49using SmbSendFn = int (*)(void *ctx, const uint8_t *data, size_t len);
50using SmbRecvFn = int (*)(void *ctx, uint8_t *buf, size_t cap);
51
52/** @brief Server credentials + the file to open. Strings are ASCII/UTF-8 (encoded UTF-16LE for you). */
53struct SmbConfig
54{
55 const char *user; ///< account name
56 const char *pass; ///< password
57 const char *domain; ///< NTLM domain (null/empty for a local account)
58 const char *workstation; ///< client name to announce (null => none)
59 const char *share; ///< the tree path, UNC `\\server\share`
60 const char *path; ///< file name relative to the share root (e.g. `PROGRAMS\A.NC`)
61 uint32_t desired_access; ///< Smb2Access::SMB2_FILE_GENERIC_READ and/or _WRITE
62 uint32_t disposition; ///< Smb2Disposition::SMB2_FILE_OPEN / _OPEN_IF / _OVERWRITE_IF / _CREATE
63};
64
65/** @brief An open file on an authenticated session; the ids thread the follow-up requests. */
66struct SmbHandle
67{
68 uint64_t session_id;
69 uint32_t tree_id;
70 uint8_t file_id[16];
71 uint64_t file_size; ///< EndofFile from CREATE (the current size)
72 uint64_t next_message_id; ///< the MessageId for the next request on this handle
73};
74
75/**
76 * @brief Run NEGOTIATE -> NTLMv2 SESSION_SETUP -> TREE_CONNECT -> CREATE and fill @p h.
77 * @return SmbResult::SMB_OK with @p h populated, or an ::SmbResult error.
78 */
79SmbResult smb_open(const SmbConfig *cfg, SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx);
80
81/**
82 * @brief CLOSE the open handle (releases the server-side FileId).
83 * @return SmbResult::SMB_OK, or an ::SmbResult error.
84 */
85SmbResult smb_close(SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx);
86
87/**
88 * @brief Read up to @p cap bytes from @p offset of the open handle, looping READ requests until the
89 * buffer is full or the server signals end of file.
90 * @param out_len receives the number of bytes actually read (may be < @p cap at EOF).
91 * @return SmbResult::SMB_OK, or an ::SmbResult error. Reads at most DETWS_SMB_BUF-sized chunks per round trip.
92 */
93SmbResult smb_read(SmbHandle *h, uint64_t offset, uint8_t *out, size_t cap, size_t *out_len, SmbSendFn send,
94 SmbRecvFn recv, void *ctx);
95
96/**
97 * @brief Write @p len bytes at @p offset of the open handle, looping WRITE requests until all bytes
98 * are acknowledged. Grows the handle's cached file_size if the write extends the file.
99 * @param written receives the number of bytes written (equals @p len on success).
100 * @return SmbResult::SMB_OK, or an ::SmbResult error.
101 */
102SmbResult smb_write(SmbHandle *h, uint64_t offset, const uint8_t *data, size_t len, size_t *written, SmbSendFn send,
103 SmbRecvFn recv, void *ctx);
104
105#endif // DETWS_ENABLE_SMB
106
107#endif // DETERMINISTICESPASYNCWEBSERVER_SMB_CLIENT_H
User-facing configuration for DeterministicESPAsyncWebServer.