ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
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 (PC_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 PROTOCORE_SMB_CLIENT_H
23#define PROTOCORE_SMB_CLIENT_H
24
25#include "protocore_config.h"
26
27#if PC_ENABLE_SMB
28
29#include "smb2.h" // Smb2SignAlgo (the per-session signing algorithm carried on the handle)
30#include <stddef.h>
31#include <stdint.h>
32
33/** @brief Result of an SMB client operation. 0 is success; each failure is a distinct code. */
34enum class SmbResult : int32_t
35{
36 SMB_OK = 0,
37 SMB_ERR_ARG = -1, ///< a required field was null/empty
38 SMB_ERR_IO = -2, ///< a send/recv failed, timed out, or the peer closed mid-message
39 SMB_ERR_PROTOCOL = -3, ///< a malformed response, or an unexpected NT status
40 SMB_ERR_AUTH = -4, ///< SESSION_SETUP was rejected (bad user/password/domain)
41 SMB_ERR_OVERFLOW = -5, ///< a message did not fit the work buffer (PC_SMB_BUF)
42};
43
44/**
45 * @brief Transport seam: the engine moves raw bytes only through these, so it runs against a real
46 * socket (pc_client) or a test mock.
47 * @return send: bytes written (must equal @p len), else < 0. recv: bytes read (> 0), else <= 0 on
48 * close / error / timeout.
49 */
50using SmbSendFn = int (*)(void *ctx, const uint8_t *data, size_t len);
51using SmbRecvFn = int (*)(void *ctx, uint8_t *buf, size_t cap);
52
53/** @brief Server credentials + the file to open. Strings are ASCII/UTF-8 (encoded UTF-16LE for you). */
54struct SmbConfig
55{
56 const char *user; ///< account name
57 const char *pass; ///< password
58 const char *domain; ///< NTLM domain (null/empty for a local account)
59 const char *workstation; ///< client name to announce (null => none)
60 const char *share; ///< the tree path, UNC `\\server\share`
61 const char *path; ///< file name relative to the share root (e.g. `PROGRAMS\A.NC`)
62 uint32_t desired_access; ///< Smb2Access::SMB2_FILE_GENERIC_READ and/or _WRITE
63 uint32_t disposition; ///< Smb2Disposition::SMB2_FILE_OPEN / _OPEN_IF / _OVERWRITE_IF / _CREATE
64 bool encrypt; ///< request SMB 3.x transport encryption from the session on (client-forced, like
65 ///< smbclient -e): needed to reach a share whose server requires encryption, which
66 ///< rejects the unencrypted TREE_CONNECT before it can advertise the share flag.
67 uint16_t cipher_pref; ///< preferred Smb2Cipher to negotiate (moved to the front of the offer); 0 = default
68 ///< order (AES-128-GCM, AES-256-GCM, AES-128-CCM, AES-256-CCM).
69};
70
71/** @brief An open file on an authenticated session; the ids thread the follow-up requests. */
72struct SmbHandle
73{
74 uint64_t session_id;
75 uint32_t tree_id;
76 uint8_t file_id[16];
77 uint64_t file_size; ///< EndofFile from CREATE (the current size)
78 uint64_t next_message_id; ///< the MessageId for the next request on this handle
79 bool signing_active; ///< the session negotiated SMB signing (server set SigningRequired, not guest/null)
80 Smb2SignAlgo signing_algo; ///< HMAC-SHA256 (SMB 2.x) or AES-CMAC (SMB 3.x), from the negotiated dialect
81 uint8_t signing_key[16]; ///< the session signing key when @ref signing_active (2.x: NTLMv2 key; 3.x: KDF-derived)
82 bool encrypt_active; ///< SMB 3.x transport encryption is in force (server session or share required it)
83 uint16_t enc_cipher; ///< negotiated Smb2Cipher id (selects the key + nonce length) when @ref encrypt_active
84 uint8_t enc_c2s[PC_SMB2_MAX_CIPHER_KEY_LEN]; ///< client->server cipher key (encrypts requests)
85 uint8_t enc_s2c[PC_SMB2_MAX_CIPHER_KEY_LEN]; ///< server->client cipher key (decrypts responses)
86 uint64_t enc_nonce; ///< monotonic per-session AEAD nonce counter, persisted across read/write/close
87};
88
89/**
90 * @brief Run NEGOTIATE -> NTLMv2 SESSION_SETUP -> TREE_CONNECT -> CREATE and fill @p h.
91 * @return SmbResult::SMB_OK with @p h populated, or an ::SmbResult error.
92 */
93SmbResult smb_open(const SmbConfig *cfg, SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx);
94
95/**
96 * @brief CLOSE the open handle (releases the server-side FileId).
97 * @return SmbResult::SMB_OK, or an ::SmbResult error.
98 */
99SmbResult smb_close(SmbHandle *h, SmbSendFn send, SmbRecvFn recv, void *ctx);
100
101/**
102 * @brief Read up to @p cap bytes from @p offset of the open handle, looping READ requests until the
103 * buffer is full or the server signals end of file.
104 * @param out_len receives the number of bytes actually read (may be < @p cap at EOF).
105 * @return SmbResult::SMB_OK, or an ::SmbResult error. Reads at most PC_SMB_BUF-sized chunks per round trip.
106 */
107SmbResult smb_read(SmbHandle *h, uint64_t offset, uint8_t *out, size_t cap, size_t *out_len, SmbSendFn send,
108 SmbRecvFn recv, void *ctx);
109
110/**
111 * @brief Write @p len bytes at @p offset of the open handle, looping WRITE requests until all bytes
112 * are acknowledged. Grows the handle's cached file_size if the write extends the file.
113 * @param written receives the number of bytes written (equals @p len on success).
114 * @return SmbResult::SMB_OK, or an ::SmbResult error.
115 */
116SmbResult smb_write(SmbHandle *h, uint64_t offset, const uint8_t *data, size_t len, size_t *written, SmbSendFn send,
117 SmbRecvFn recv, void *ctx);
118
119#endif // PC_ENABLE_SMB
120
121#endif // PROTOCORE_SMB_CLIENT_H
User-facing configuration for ProtoCore.
SMB2 client wire codec (MS-SMB2), PC_ENABLE_SMB - increment 1: the transport frame,...