FreeRDP
Loading...
Searching...
No Matches
TestSAM.c
1#include <stdlib.h>
2#include <string.h>
3
4#include <winpr/wtypes.h>
5#include <winpr/string.h>
6#include <winpr/sam.h>
7#include <winpr/file.h>
8#include <winpr/crypto.h>
9#include <winpr/path.h>
10
11const char* sam_entries[] = {
12 "test1:::1910bd9285a6b8c9344d9f5cc74e0878:::", /* test1, xxxxxx */
13 "test2:::1bfc28ca2a4c218b032f4a0309b31f20:::", /* test2, aaaaaabbbbbb */
14 "test1:domain::eab3412c36d6bbb1e3f6eaaf2775696e:::" /* test1, domain, pppppppp */
15};
16
17typedef struct
18{
19 const char* pwd;
20 BYTE LmHash[16];
21 BYTE NtHash[16];
22} test_case_t;
23
24const test_case_t hashes[] = { { .pwd = "xxxxxx",
25 .LmHash = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
27 .NtHash = { 0x19, 0x10, 0xbd, 0x92, 0x85, 0xa6, 0xb8, 0xc9, 0x34,
28 0x4d, 0x9f, 0x5c, 0xc7, 0x4e, 0x08, 0x78 } },
29 { .pwd = "aaaaaabbbbbb",
30 .LmHash = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
32 .NtHash = { 0x1b, 0xfc, 0x28, 0xca, 0x2a, 0x4c, 0x21, 0x8b, 0x03,
33 0x2f, 0x4a, 0x03, 0x09, 0xb3, 0x1f, 0x20 } },
34 { .pwd = "pppppppp",
35 .LmHash = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
37 .NtHash = { 0xea, 0xb3, 0x41, 0x2c, 0x36, 0xd6, 0xbb, 0xb1, 0xe3,
38 0xf6, 0xea, 0xaf, 0x27, 0x75, 0x69, 0x6e } } };
39
40static BOOL testHashA(const WINPR_SAM_ENTRY* entry, const char* pwd)
41{
42 if (!entry)
43 return FALSE;
44 for (size_t x = 0; x < ARRAYSIZE(hashes); x++)
45 {
46 const test_case_t* cur = &hashes[x];
47 if (strcmp(cur->pwd, pwd) != 0)
48 continue;
49
50 if (memcmp(entry->LmHash, cur->LmHash, sizeof(entry->LmHash)) != 0)
51 return FALSE;
52 return (memcmp(entry->NtHash, cur->NtHash, sizeof(entry->NtHash)) == 0);
53 }
54 return FALSE;
55}
56
57static BOOL testHashW(const WINPR_SAM_ENTRY* entry, const WCHAR* pwd)
58{
59 if (!pwd)
60 return FALSE;
61 char* pwdA = ConvertWCharToUtf8Alloc(pwd, nullptr);
62 if (!pwdA)
63 return FALSE;
64 const BOOL rc = testHashA(entry, pwdA);
65 free(pwdA);
66 return rc;
67}
68
69static BOOL testA(WINPR_SAM* sam, const char* name, const char* domain, const char* pwd,
70 BOOL expectSuccess)
71{
72 BOOL rc = !expectSuccess;
73 size_t nlen = 0;
74 if (name)
75 nlen = strlen(name);
76
77 size_t dlen = 0;
78 if (domain)
79 dlen = strlen(domain);
80
81 WINPR_SAM_ENTRY* entry = SamLookupUserA(sam, name, nlen, domain, dlen);
82 if (!entry)
83 goto fail;
84
85 if (entry->UserLength != nlen)
86 goto fail;
87 if (entry->DomainLength != dlen)
88 goto fail;
89
90 if (name)
91 {
92 if (strncmp(name, entry->User, nlen + 1) != 0)
93 goto fail;
94 }
95
96 if (domain)
97 {
98 if (strncmp(domain, entry->Domain, dlen + 1) != 0)
99 goto fail;
100 }
101
102 rc = testHashA(entry, pwd);
103 if (!expectSuccess)
104 rc = !rc;
105
106fail:
107 SamFreeEntry(sam, entry);
108 return rc;
109}
110
111static BOOL testW(WINPR_SAM* sam, const WCHAR* name, const WCHAR* domain, const WCHAR* pwd,
112 BOOL expectSuccess)
113{
114 BOOL rc = !expectSuccess;
115 size_t nlen = 0;
116 if (name)
117 nlen = _wcslen(name) * sizeof(WCHAR);
118
119 size_t dlen = 0;
120 if (domain)
121 dlen = _wcslen(domain) * sizeof(WCHAR);
122
123 WINPR_SAM_ENTRY* entry = SamLookupUserW(sam, name, nlen, domain, dlen);
124 if (!entry)
125 goto fail;
126
127 if (entry->UserLength != nlen)
128 goto fail;
129 if (entry->DomainLength != dlen)
130 goto fail;
131
132 if (name)
133 {
134 if (_wcsncmp(name, (const WCHAR*)entry->User, nlen / sizeof(WCHAR) + 1) != 0)
135 goto fail;
136 }
137
138 if (domain)
139 {
140 if (_wcsncmp(domain, (const WCHAR*)entry->Domain, dlen / sizeof(WCHAR) + 1) != 0)
141 goto fail;
142 }
143
144 rc = testHashW(entry, pwd);
145 if (!expectSuccess)
146 rc = !rc;
147
148fail:
149 SamFreeEntry(sam, entry);
150 return rc;
151}
152
153static BOOL test(WINPR_SAM* sam, const char* name, const char* domain, const char* pwd,
154 BOOL expectSuccess)
155{
156 if (!testA(sam, name, domain, pwd, expectSuccess))
157 return FALSE;
158
159 WCHAR* nameW = nullptr;
160 WCHAR* domainW = nullptr;
161 WCHAR* pwdW = nullptr;
162 if (name)
163 nameW = ConvertUtf8ToWCharAlloc(name, nullptr);
164 if (domain)
165 domainW = ConvertUtf8ToWCharAlloc(domain, nullptr);
166 if (pwd)
167 pwdW = ConvertUtf8ToWCharAlloc(pwd, nullptr);
168
169 const BOOL rc = testW(sam, nameW, domainW, pwdW, expectSuccess);
170fail:
171 free(nameW);
172 free(domainW);
173 free(pwdW);
174 return rc;
175}
176
177WINPR_ATTR_MALLOC(free, 1)
178static char* prepare(void)
179{
180 char tpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
181
182 size_t nr = 0;
183 if (winpr_RAND(&nr, sizeof(nr)) < 0)
184 return nullptr;
185 (void)snprintf(tpath, sizeof(tpath), "sam-test-%016" PRIxz, nr);
186 char* tmp = GetKnownSubPath(KNOWN_PATH_TEMP, tpath);
187 if (!tmp)
188 return nullptr;
189
190 FILE* fp = fopen(tmp, "w");
191 if (!fp)
192 {
193 free(tmp);
194 return nullptr;
195 }
196
197 for (size_t x = 0; x < ARRAYSIZE(sam_entries); x++)
198 {
199 const char* entry = sam_entries[x];
200 (void)fprintf(fp, "%s\r\n", entry);
201 }
202 (void)fclose(fp);
203
204 return tmp;
205}
206
207int TestSAM(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[])
208{
209 int res = -1;
210
211 char* tmp = prepare();
212 if (!tmp)
213 return -1;
214
215 WINPR_SAM* sam = SamOpen(tmp, TRUE);
216 if (!sam)
217 goto fail;
218
219 if (!test(sam, "test1", nullptr, "xxxxxx", TRUE))
220 goto fail;
221 if (!test(sam, "test2", nullptr, "aaaaaabbbbbb", TRUE))
222 goto fail;
223 if (!test(sam, "test1", "domain", "pppppppp", TRUE))
224 goto fail;
225 if (!test(sam, "test1", "foobar", "xxxxxx", FALSE))
226 goto fail;
227 if (!test(sam, "test3", nullptr, "xxxxxx", FALSE))
228 goto fail;
229 if (!test(sam, "test1", nullptr, "xxxxxxe", FALSE))
230 goto fail;
231
232 res = 0;
233fail:
234 SamClose(sam);
235 if (tmp)
236 DeleteFile(tmp);
237 free(tmp);
238 return res;
239}