ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
smb_client.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_SMB_CLIENT_H
5#define PROTOCORE_SMB_CLIENT_H
6
7#include "network_drivers/application/smb/smb2/smb2.h" // the complete type a public struct below holds by value
8#include "protocore_config.h" // the entry point: protocore_types.h for the widths
9
11
12/**
13 * @file smb_client.h
14 * @brief SMB2 client dialogue engine (PROTOCORE_ENABLE_SMB) - drives the smb2 / ntlm / spnego wire
15codecs through a real session to open a file on a Windows share.
16 *
17 * The wire codecs (smb2.h, ntlm.h, ntlmssp.h, spnego.h) are pure builders/parsers; this ties them
18 * into the actual exchange: NEGOTIATE, the two-round NTLMv2 SESSION_SETUP (SPNEGO-wrapped),
19 * TREE_CONNECT to `\\server\share`, and CREATE to open the file - handing back a handle that
20 * smb_read / smb_write / smb_close use. Like the SMTP engine it is written against a send/recv seam,
21 * so the whole exchange is host-tested with a scripted mock SMB2 server (no lwIP / real share).
22 *
23 * Direct-TCP framing (the 4-byte length prefix) is handled here: each request is framed before
24 * `send`, each response is de-framed after `recv` (accumulating until a full message arrives).
25 *
26 * @c work is PROTOCORE_SMB_CLIENT_BORROW bytes the CALLER took, at an address it knows. It is not held past the call,
27so nothing here aliases it. How those bytes are
28 * carved is this module's and is never named here.
29 *
30 * @author Douglas Quigg (dstroy0)
31 * @date 2026
32 */
33
34/** @brief Result of an SMB client operation. 0 is success; each failure is a distinct code. */
36{
37 SMB_OK = 0,
38 SMB_ERR_ARG = -1, ///< a required field was null/empty
39 SMB_ERR_IO = -2, ///< a send/recv failed, timed out, or the peer closed mid-message
40 SMB_ERR_PROTOCOL = -3, ///< a malformed response, or an unexpected NT status
41 SMB_ERR_AUTH = -4, ///< SESSION_SETUP was rejected (bad user/password/domain)
42 SMB_ERR_OVERFLOW = -5, ///< a message did not fit the work buffer (PROTOCORE_SMB_BUF)
44
45/**
46 * @brief Transport seam: the engine moves raw bytes only through these, so it runs against a real
47 * socket (protocore_client) or a test mock.
48 * @return send: bytes written (must equal @p len), else < 0. recv: bytes read (> 0), else <= 0 on
49 * close / error / timeout.
50 */
51typedef int (*SmbSendFn)(void *ctx, const uint8_t *data, size_t len);
52
53typedef int (*SmbRecvFn)(void *ctx, uint8_t *buf, size_t cap);
54
55/** @brief Server credentials + the file to open. Strings are ASCII/UTF-8 (encoded UTF-16LE for you). */
56typedef struct
57{
58 const char *user; ///< account name
59 const char *pass; ///< password
60 const char *domain; ///< NTLM domain (null/empty for a local account)
61 const char *workstation; ///< client name to announce (null => none)
62 const char *share; ///< the tree path, UNC `\\server\share`
63 const char *path; ///< file name relative to the share root (e.g. `PROGRAMS\A.NC`)
64 uint32_t desired_access; ///< SMB2_FILE_GENERIC_READ and/or _WRITE
65 uint32_t disposition; ///< SMB2_FILE_OPEN / _OPEN_IF / _OVERWRITE_IF / _CREATE
66 proto_bool encrypt; ///< request SMB 3.x transport encryption from the session on (client-forced, like
67 ///< smbclient -e): needed to reach a share whose server requires encryption, which
68 ///< rejects the unencrypted TREE_CONNECT before it can advertise the share flag.
69 uint16_t cipher_pref; ///< preferred Smb2Cipher to negotiate (moved to the front of the offer); 0 = default
70 ///< order (AES-128-GCM, AES-256-GCM, AES-128-CCM, AES-256-CCM).
71} SmbConfig;
72
73/** @brief An open file on an authenticated session; the ids thread the follow-up requests. */
74typedef struct
75{
76 uint64_t session_id;
77 uint32_t tree_id;
78 uint8_t file_id[16];
79 uint64_t file_size; ///< EndofFile from CREATE (the current size)
80 uint64_t next_message_id; ///< the MessageId for the next request on this handle
81 proto_bool signing_active; ///< the session negotiated SMB signing (server set SigningRequired, not guest/null)
82 Smb2SignAlgo signing_algo; ///< HMAC-SHA256 (SMB 2.x) or AES-CMAC (SMB 3.x), from the negotiated dialect
83 uint8_t signing_key[16]; ///< the session signing key when @ref signing_active (2.x: NTLMv2 key; 3.x: KDF-derived)
84 proto_bool encrypt_active; ///< SMB 3.x transport encryption is in force (server session or share required it)
85 uint16_t enc_cipher; ///< negotiated Smb2Cipher id (selects the key + nonce length) when @ref encrypt_active
86 uint8_t enc_c2s[PROTOCORE_SMB2_MAX_CIPHER_KEY_LEN]; ///< client->server cipher key (encrypts requests)
87 uint8_t enc_s2c[PROTOCORE_SMB2_MAX_CIPHER_KEY_LEN]; ///< server->client cipher key (decrypts responses)
88 uint64_t enc_nonce; ///< monotonic per-session AEAD nonce counter, persisted across read/write/close
89} SmbHandle;
90
91/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
92typedef struct
93{
94 SmbResult (*smb_open)(uint8_t *, const SmbConfig *, SmbHandle *, SmbSendFn, SmbRecvFn, void *);
95 SmbResult (*smb_close)(uint8_t *, SmbHandle *, SmbSendFn, SmbRecvFn, void *);
96 SmbResult (*smb_read)(uint8_t *, SmbHandle *, uint64_t, uint8_t *, size_t, size_t *, SmbSendFn, SmbRecvFn, void *);
97 SmbResult (*smb_write)(uint8_t *, SmbHandle *, uint64_t, const uint8_t *, size_t, size_t *, SmbSendFn, SmbRecvFn,
98 void *);
100PROTOCORE_NS_LAYOUT(SmbClientNs, smb_open, smb_close, smb_read, smb_write);
101
102/**
103 * @brief Run NEGOTIATE -> NTLMv2 SESSION_SETUP -> TREE_CONNECT -> CREATE and .
104 * @param work PROTOCORE_SMB_CLIENT_BORROW bytes the caller took. Not held past the call.
105 * @param cfg Cfg
106 * @param h H
107 * @param send Send
108 * @param recv Recv
109 * @param ctx Ctx
110 * @return The SmbResult.
111 */
113 SmbRecvFn recv, void *ctx);
114/**
115 * @brief CLOSE the open handle (releases the server-side FileId).
116 * @param work PROTOCORE_SMB_CLIENT_BORROW bytes the caller took. Not held past the call.
117 * @param h H
118 * @param send Send
119 * @param recv Recv
120 * @param ctx Ctx
121 * @return The SmbResult.
122 */
123SmbResult protocore_smb_client_smb_close(uint8_t *work, SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx);
124/**
125 * @brief Read up to cap bytes from offset of the open handle, looping READ .
126 * @param work PROTOCORE_SMB_CLIENT_BORROW bytes the caller took. Not held past the call.
127 * @param h H
128 * @param offset Offset
129 * @param out Out
130 * @param cap Cap
131 * @param out_len receives the number of bytes actually read (may be < cap at EOF)
132 * @param send Send
133 * @param recv Recv
134 * @param ctx Ctx
135 * @return The SmbResult.
136 */
137SmbResult protocore_smb_client_smb_read(uint8_t *work, SmbHandle *h, uint64_t offset, uint8_t *out, size_t cap,
138 size_t *out_len, SmbSendFn send, SmbRecvFn recv, void *ctx);
139/**
140 * @brief Write len bytes at offset of the open handle, looping WRITE .
141 * @param work PROTOCORE_SMB_CLIENT_BORROW bytes the caller took. Not held past the call.
142 * @param h H
143 * @param offset Offset
144 * @param data Data
145 * @param len Len
146 * @param written receives the number of bytes written (equals len on success)
147 * @param send Send
148 * @param recv Recv
149 * @param ctx Ctx
150 * @return The SmbResult.
151 */
152SmbResult protocore_smb_client_smb_write(uint8_t *work, SmbHandle *h, uint64_t offset, const uint8_t *data, size_t len,
153 size_t *written, SmbSendFn send, SmbRecvFn recv, void *ctx);
154
155/**
156 * @brief Transport seam: the engine moves raw bytes only through these, so it runs against a real
157 * socket (protocore_client) or a test mock.
158 * @return send: bytes written (must equal @p len), else < 0. recv: bytes read (> 0), else <= 0 on
159 * close / error / timeout.
160 */
161typedef int (*SmbSendFn)(void *ctx, const uint8_t *data, size_t len);
162/**
163 * @brief The PROTOCORE_SMB_CLIENT_BORROW bytes this module's state lives in.
164 *
165 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
166 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
167 * walks, so the state lasts the life of the program.
168 *
169 * @return the span.
170 */
172
173/** @brief Module namespace. */
178
180
181#endif // PROTOCORE_SMB_CLIENT_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
SMB2 client wire codec (MS-SMB2), PROTOCORE_ENABLE_SMB - increment 1: the transport frame,...
#define PROTOCORE_SMB2_MAX_CIPHER_KEY_LEN
Largest cipher key length across the four SMB 3.1.1 ciphers (AES-256), for buffer sizing.
Definition smb2.h:157
enum PROTO_ENUM_PACKED Smb2SignAlgo
The per-session message-signing algorithm the client selects from the negotiated dialect.
SmbResult protocore_smb_client_smb_open(uint8_t *work, const SmbConfig *cfg, SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx)
Run NEGOTIATE -> NTLMv2 SESSION_SETUP -> TREE_CONNECT -> CREATE and .
enum PROTO_ENUM_PACKED SmbResult
Result of an SMB client operation. 0 is success; each failure is a distinct code.
int(* SmbRecvFn)(void *ctx, uint8_t *buf, size_t cap)
Definition smb_client.h:53
int(* SmbSendFn)(void *ctx, const uint8_t *data, size_t len)
Transport seam: the engine moves raw bytes only through these, so it runs against a real socket (prot...
Definition smb_client.h:51
uint8_t * protocore_smb_client_span(void)
The PROTOCORE_SMB_CLIENT_BORROW bytes this module's state lives in.
SmbResult protocore_smb_client_smb_write(uint8_t *work, SmbHandle *h, uint64_t offset, const uint8_t *data, size_t len, size_t *written, SmbSendFn send, SmbRecvFn recv, void *ctx)
Write len bytes at offset of the open handle, looping WRITE .
PROTOCORE_NS SmbClientNs SmbClient PROTOCORE_UNUSED
Module namespace.
Definition smb_client.h:174
@ SMB_ERR_ARG
a required field was null/empty
Definition smb_client.h:38
@ SMB_ERR_AUTH
SESSION_SETUP was rejected (bad user/password/domain)
Definition smb_client.h:41
@ SMB_OK
Definition smb_client.h:37
@ SMB_ERR_PROTOCOL
a malformed response, or an unexpected NT status
Definition smb_client.h:40
@ SMB_ERR_OVERFLOW
a message did not fit the work buffer (PROTOCORE_SMB_BUF)
Definition smb_client.h:42
@ SMB_ERR_IO
a send/recv failed, timed out, or the peer closed mid-message
Definition smb_client.h:39
SmbResult protocore_smb_client_smb_close(uint8_t *work, SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx)
CLOSE the open handle (releases the server-side FileId).
SmbResult protocore_smb_client_smb_read(uint8_t *work, SmbHandle *h, uint64_t offset, uint8_t *out, size_t cap, size_t *out_len, SmbSendFn send, SmbRecvFn recv, void *ctx)
Read up to cap bytes from offset of the open handle, looping READ .
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition smb_client.h:93
SmbResult(* smb_open)(uint8_t *, const SmbConfig *, SmbHandle *, SmbSendFn, SmbRecvFn, void *)
Definition smb_client.h:94
Server credentials + the file to open. Strings are ASCII/UTF-8 (encoded UTF-16LE for you).
Definition smb_client.h:57
const char * path
file name relative to the share root (e.g. PROGRAMS\A.NC)
Definition smb_client.h:63
uint32_t disposition
SMB2_FILE_OPEN / _OPEN_IF / _OVERWRITE_IF / _CREATE.
Definition smb_client.h:65
uint16_t cipher_pref
Definition smb_client.h:69
const char * workstation
client name to announce (null => none)
Definition smb_client.h:61
proto_bool encrypt
Definition smb_client.h:66
const char * user
account name
Definition smb_client.h:58
uint32_t desired_access
SMB2_FILE_GENERIC_READ and/or _WRITE.
Definition smb_client.h:64
const char * pass
password
Definition smb_client.h:59
const char * share
the tree path, UNC \\server\share
Definition smb_client.h:62
const char * domain
NTLM domain (null/empty for a local account)
Definition smb_client.h:60
An open file on an authenticated session; the ids thread the follow-up requests.
Definition smb_client.h:75
proto_bool signing_active
the session negotiated SMB signing (server set SigningRequired, not guest/null)
Definition smb_client.h:81
uint64_t enc_nonce
monotonic per-session AEAD nonce counter, persisted across read/write/close
Definition smb_client.h:88
uint64_t next_message_id
the MessageId for the next request on this handle
Definition smb_client.h:80
proto_bool encrypt_active
SMB 3.x transport encryption is in force (server session or share required it)
Definition smb_client.h:84
uint64_t file_size
EndofFile from CREATE (the current size)
Definition smb_client.h:79
Smb2SignAlgo signing_algo
HMAC-SHA256 (SMB 2.x) or AES-CMAC (SMB 3.x), from the negotiated dialect.
Definition smb_client.h:82
uint32_t tree_id
Definition smb_client.h:77
uint16_t enc_cipher
negotiated Smb2Cipher id (selects the key + nonce length) when encrypt_active
Definition smb_client.h:85
uint64_t session_id
Definition smb_client.h:76
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97