1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <poll.h>
#include <memory>
#include <smb2/smb2.h>
#include <smb2/libsmb2.h>

// 统一的同步回调数据结构
struct WaitCbData {
bool is_finished{false};
int status{0};
void* ptr{nullptr};
};

// 公用的同步等待轮询函数
auto WaitForReply(struct smb2_context* smb2,
std::shared_ptr<WaitCbData> cb_data) -> int {
while (!cb_data->is_finished) {
struct pollfd pfd{};
pfd.fd = smb2_get_fd(smb2);
pfd.events = smb2_which_events(smb2);

if (poll(&pfd, 1, 1000) < 0) {
return -1;
}
if (pfd.revents == 0) {
continue;
}
if (smb2_service(smb2, pfd.revents) < 0) {
return -1;
}
}
return 0;
}

// =========================================================
// 1. Close 接口封装 (解决 UAF 与 Double-Free)
// =========================================================

auto CloseFileCb(struct smb2_context* smb2, int status,
void* command_data, void* private_data) -> void {
auto* sp = static_cast<std::shared_ptr<WaitCbData>*>(private_data);
if (sp == nullptr) return;

if (status != SMB2_STATUS_SHUTDOWN && *sp) {
(*sp)->is_finished = true;
(*sp)->status = status;
}
delete sp;
}

auto Smb2CloseSync(struct smb2_context* smb2, struct smb2fh* fh) -> int {
auto cb_data = std::make_shared<WaitCbData>();
auto* cb_ptr = new std::shared_ptr<WaitCbData>(cb_data);

if (smb2_close_async(smb2, fh, CloseFileCb, cb_ptr) < 0) {
delete cb_ptr;
return -1;
}

if (WaitForReply(smb2, cb_data) < 0) {
return -1; // 异常退出,保留 cb_ptr,由 CloseFileCb 安全回收
}
return cb_data->status;
}

// =========================================================
// 2. OpenDir 接口封装 (解决 UAF 与所有权转移)
// =========================================================

auto OpenDirCb(struct smb2_context* smb2, int status,
void* command_data, void* private_data) -> void {
auto* sp = static_cast<std::shared_ptr<WaitCbData>*>(private_data);
if (sp == nullptr) return;

if (status != SMB2_STATUS_SHUTDOWN && *sp) {
(*sp)->is_finished = true;
(*sp)->status = status;
(*sp)->ptr = command_data;
}

// 成功获取目录指针时,禁止释放 sp,必须将生命周期委托给 smb2dir
if (status == 0 && command_data != nullptr) {
return;
}
delete sp;
}

auto Smb2OpenDirSync(struct smb2_context* smb2,
const char* path) -> struct smb2dir* {
auto cb_data = std::make_shared<WaitCbData>();
auto* cb_ptr = new std::shared_ptr<WaitCbData>(cb_data);

auto* pdu = smb2_opendir_async_pdu(smb2, path, OpenDirCb, cb_ptr, nullptr);
if (pdu == nullptr) {
delete cb_ptr;
return nullptr;
}

if (WaitForReply(smb2, cb_data) < 0) {
smb2_free_pdu(smb2, pdu);
return nullptr;
}

auto* dir = static_cast<struct smb2dir*>(cb_data->ptr);
if (dir != nullptr) {
// 利用 C++17 无捕获 Lambda 隐式转换为 C 函数指针,安全处理资源释放
dir->free_cb_data = [](void* ptr) {
delete static_cast<std::shared_ptr<WaitCbData>*>(ptr);
};
}

smb2_free_pdu(smb2, pdu);
return dir;
}

// =========================================================
// 3. ShareEnum 接口封装 (解决超时内存泄漏)
// =========================================================

auto ShareEnumCb(struct smb2_context* smb2, int status,
void* command_data, void* private_data) -> void {
auto* sp = static_cast<std::shared_ptr<WaitCbData>*>(private_data);
if (sp == nullptr) return;

if (status != SMB2_STATUS_SHUTDOWN && *sp) {
(*sp)->is_finished = true;
(*sp)->status = status;
(*sp)->ptr = command_data;
}
delete sp;
}

auto Smb2ShareEnumSync(struct smb2_context* smb2,
enum SHARE_INFO_enum level) -> struct srvsvc_NetrShareEnum_rep* {
auto cb_data = std::make_shared<WaitCbData>();
auto* cb_ptr = new std::shared_ptr<WaitCbData>(cb_data);

if (smb2_share_enum_async(smb2, level, ShareEnumCb, cb_ptr) < 0) {
delete cb_ptr;
return nullptr;
}

// 原生代码在此处出错时直接 return NULL 导致失控。
// 此处即使 return,cb_ptr 也必然会被迟滞触发的 ShareEnumCb 回收,完美避免泄露。
if (WaitForReply(smb2, cb_data) < 0) {
return nullptr;
}

return static_cast<struct srvsvc_NetrShareEnum_rep*>(cb_data->ptr);
}