1 /*
2 * PROJECT: ReactOS NetSh
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Network Shell helper dll management and support functions
5 * COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include "precomp.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 PDLL_LIST_ENTRY pDllListHead = NULL;
18 PDLL_LIST_ENTRY pDllListTail = NULL;
19
20 PHELPER_ENTRY pHelperListHead = NULL;
21 PHELPER_ENTRY pHelperListTail = NULL;
22
23 PDLL_LIST_ENTRY pCurrentDll = NULL;
24
25 /* FUNCTIONS ******************************************************************/
26
27 static
28 VOID
StartHelpers(VOID)29 StartHelpers(VOID)
30 {
31 PHELPER_ENTRY pHelper;
32 DWORD dwError;
33
34 pHelper = pHelperListHead;
35 while (pHelper != NULL)
36 {
37 if (pHelper->bStarted == FALSE)
38 {
39 if (pHelper->Attributes.pfnStart)
40 {
41 dwError = pHelper->Attributes.pfnStart(NULL, 0);
42 if (dwError == ERROR_SUCCESS)
43 pHelper->bStarted = TRUE;
44 }
45 }
46
47 pHelper = pHelper->pNext;
48 }
49 }
50
51
52 static
53 VOID
RegisterHelperDll(_In_ PDLL_LIST_ENTRY pEntry)54 RegisterHelperDll(
55 _In_ PDLL_LIST_ENTRY pEntry)
56 {
57 PWSTR pszValueName = NULL;
58 HKEY hKey;
59 DWORD dwError;
60
61 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
62 REG_NETSH_PATH,
63 0,
64 NULL,
65 REG_OPTION_NON_VOLATILE,
66 KEY_WRITE,
67 NULL,
68 &hKey,
69 NULL);
70 if (dwError == ERROR_SUCCESS)
71 {
72 RegSetValueExW(hKey,
73 pEntry->pszValueName,
74 0,
75 REG_SZ,
76 (PBYTE)pEntry->pszDllName,
77 (wcslen(pEntry->pszDllName) + 1) * sizeof(WCHAR));
78
79 RegCloseKey(hKey);
80 }
81
82 HeapFree(GetProcessHeap(), 0, pszValueName);
83 }
84
85
86 static
87 VOID
FreeHelperDll(_In_ PDLL_LIST_ENTRY pEntry)88 FreeHelperDll(
89 _In_ PDLL_LIST_ENTRY pEntry)
90 {
91 if (pEntry->hModule)
92 FreeLibrary(pEntry->hModule);
93
94 if (pEntry->pszValueName)
95 HeapFree(GetProcessHeap(), 0, pEntry->pszValueName);
96
97 if (pEntry->pszShortName)
98 HeapFree(GetProcessHeap(), 0, pEntry->pszShortName);
99
100 if (pEntry->pszDllName)
101 HeapFree(GetProcessHeap(), 0, pEntry->pszDllName);
102
103 HeapFree(GetProcessHeap(), 0, pEntry);
104 }
105
106
107 static
108 DWORD
LoadHelperDll(_In_ PWSTR pszDllName,_In_ BOOL bRegister)109 LoadHelperDll(
110 _In_ PWSTR pszDllName,
111 _In_ BOOL bRegister)
112 {
113 PNS_DLL_INIT_FN pInitHelperDll;
114 PDLL_LIST_ENTRY pEntry;
115 PWSTR pszStart, pszEnd;
116 BOOL bInserted = FALSE;
117 DWORD dwError;
118
119 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DLL_LIST_ENTRY));
120 if (pEntry == NULL)
121 {
122 return ERROR_OUTOFMEMORY;
123 }
124
125 pEntry->pszDllName = HeapAlloc(GetProcessHeap(),
126 HEAP_ZERO_MEMORY,
127 (wcslen(pszDllName) + 1) * sizeof(WCHAR));
128 if (pEntry->pszDllName == NULL)
129 {
130 dwError = ERROR_OUTOFMEMORY;
131 goto done;
132 }
133
134 wcscpy(pEntry->pszDllName, pszDllName);
135
136 pszStart = wcsrchr(pszDllName, L'\\');
137 if (pszStart == NULL)
138 pszStart = pszDllName;
139
140 pEntry->pszShortName = HeapAlloc(GetProcessHeap(),
141 HEAP_ZERO_MEMORY,
142 (wcslen(pszStart) + 1) * sizeof(WCHAR));
143 if (pEntry->pszShortName == NULL)
144 {
145 dwError = ERROR_OUTOFMEMORY;
146 goto done;
147 }
148
149 wcscpy(pEntry->pszShortName, pszStart);
150
151 pEntry->pszValueName = HeapAlloc(GetProcessHeap(),
152 HEAP_ZERO_MEMORY,
153 (wcslen(pEntry->pszShortName) + 1) * sizeof(WCHAR));
154 if (pEntry->pszValueName == NULL)
155 {
156 dwError = ERROR_OUTOFMEMORY;
157 goto done;
158 }
159
160 wcscpy(pEntry->pszValueName, pEntry->pszShortName);
161
162 pszEnd = wcsrchr(pEntry->pszValueName, L'.');
163 if (pszEnd != NULL)
164 *pszEnd = UNICODE_NULL;
165
166 if (pDllListTail == NULL)
167 {
168 pEntry->pPrev = NULL;
169 pEntry->pNext = NULL;
170 pDllListHead = pEntry;
171 pDllListTail = pEntry;
172 }
173 else
174 {
175 pEntry->pPrev = NULL;
176 pEntry->pNext = pDllListHead;
177 pDllListHead->pPrev = pEntry;
178 pDllListHead = pEntry;
179 }
180
181 bInserted = TRUE;
182
183 pEntry->hModule = LoadLibraryW(pEntry->pszDllName);
184 if (pEntry->hModule == NULL)
185 {
186 dwError = GetLastError();
187 DPRINT1("Could not load the helper dll %S (Error: %lu)\n", pEntry->pszDllName, dwError);
188 goto done;
189 }
190
191 pInitHelperDll = (PNS_DLL_INIT_FN)GetProcAddress(pEntry->hModule, "InitHelperDll");
192 if (pInitHelperDll == NULL)
193 {
194 dwError = GetLastError();
195 DPRINT1("Could not find 'InitHelperDll' (Error: %lu)\n", dwError);
196 goto done;
197 }
198
199 pCurrentDll = pEntry;
200 dwError = pInitHelperDll(5, NULL);
201 pCurrentDll = NULL;
202
203 DPRINT1("InitHelperDll returned %lu\n", dwError);
204 if (dwError != ERROR_SUCCESS)
205 {
206 DPRINT1("Call to InitHelperDll failed (Error: %lu)\n", dwError);
207 goto done;
208 }
209
210 // if (pEntry->Attributes.pfnStart)
211 // pEntry->Attributes.pfnStart(NULL, 0);
212
213 if (bRegister)
214 RegisterHelperDll(pEntry);
215
216 done:
217 if (dwError != ERROR_SUCCESS)
218 {
219 if (bInserted)
220 {
221 if (pEntry->pPrev != NULL)
222 pEntry->pPrev->pNext = pEntry->pNext;
223 if (pEntry->pNext != NULL)
224 pEntry->pNext->pPrev = pEntry->pPrev;
225 if (pDllListTail == pEntry)
226 pDllListTail = pEntry->pPrev;
227 if (pDllListHead == pEntry)
228 pDllListHead = pEntry->pNext;
229 pEntry->pPrev = NULL;
230 pEntry->pNext = NULL;
231 }
232
233 FreeHelperDll(pEntry);
234 }
235
236 return dwError;
237 }
238
239
240 VOID
LoadHelpers(VOID)241 LoadHelpers(VOID)
242 {
243 PWSTR pszNameBuffer = NULL;
244 PWSTR pszValueBuffer = NULL;
245 HKEY hKey;
246 DWORD dwValueCount, dwMaxNameLength, dwMaxValueLength;
247 DWORD dwNameLength, dwValueLength, dwType;
248 DWORD dwIndex, dwError;
249
250 DPRINT1("LoadHelpers()\n");
251
252 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
253 REG_NETSH_PATH,
254 0,
255 KEY_READ,
256 &hKey);
257 if (dwError != ERROR_SUCCESS)
258 return;
259
260 dwError = RegQueryInfoKeyW(hKey,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 NULL,
266 NULL,
267 &dwValueCount,
268 &dwMaxNameLength,
269 &dwMaxValueLength,
270 NULL,
271 NULL);
272 if (dwError != ERROR_SUCCESS)
273 goto done;
274
275 pszNameBuffer = HeapAlloc(GetProcessHeap(), 0,
276 (dwMaxNameLength + 1) * sizeof(WCHAR));
277 if (pszNameBuffer == NULL)
278 goto done;
279
280 pszValueBuffer = HeapAlloc(GetProcessHeap(), 0,
281 dwMaxValueLength + sizeof(WCHAR));
282 if (pszValueBuffer == NULL)
283 goto done;
284
285 for (dwIndex = 0; dwIndex < dwValueCount; dwIndex++)
286 {
287 dwNameLength = dwMaxNameLength + 1;
288 dwValueLength = dwMaxValueLength + sizeof(WCHAR);
289 dwError = RegEnumValueW(hKey,
290 dwIndex,
291 pszNameBuffer,
292 &dwNameLength,
293 NULL,
294 &dwType,
295 (PBYTE)pszValueBuffer,
296 &dwValueLength);
297 if (dwError != ERROR_SUCCESS)
298 break;
299
300 DPRINT1("Dll: %S --> %S %lu\n", pszNameBuffer, pszValueBuffer, dwError);
301 LoadHelperDll(pszValueBuffer, FALSE);
302 }
303
304 done:
305 if (pszValueBuffer)
306 HeapFree(GetProcessHeap(), 0, pszValueBuffer);
307
308 if (pszNameBuffer)
309 HeapFree(GetProcessHeap(), 0, pszNameBuffer);
310
311 RegCloseKey(hKey);
312
313 StartHelpers();
314 }
315
316
317 VOID
UnloadHelpers(VOID)318 UnloadHelpers(VOID)
319 {
320 PDLL_LIST_ENTRY pEntry;
321
322 while (pDllListHead != NULL)
323 {
324 pEntry = pDllListHead;
325 pDllListHead = pEntry->pNext;
326
327 // if (pEntry->Attributes.pfnStop)
328 // pEntry->Attributes.pfnStop(0);
329
330 FreeHelperDll(pEntry);
331 }
332
333 pDllListTail = NULL;
334 }
335
336
337 PHELPER_ENTRY
FindHelper(_In_ const GUID * pguidHelper)338 FindHelper(
339 _In_ const GUID *pguidHelper)
340 {
341 PHELPER_ENTRY pHelper;
342
343 pHelper = pHelperListHead;
344 while (pHelper != NULL)
345 {
346 if (IsEqualGUID(pguidHelper, &pHelper->Attributes.guidHelper))
347 return pHelper;
348
349 pHelper = pHelper->pNext;
350 }
351
352 return NULL;
353 }
354
355
356 DWORD
357 WINAPI
RegisterHelper(_In_ const GUID * pguidParentHelper,_In_ const NS_HELPER_ATTRIBUTES * pHelperAttributes)358 RegisterHelper(
359 _In_ const GUID *pguidParentHelper,
360 _In_ const NS_HELPER_ATTRIBUTES *pHelperAttributes)
361 {
362 PHELPER_ENTRY pHelper = NULL, pParentHelper;
363 DWORD dwError = ERROR_SUCCESS;
364
365 DPRINT("RegisterHelper(%p %p)\n", pguidParentHelper, pHelperAttributes);
366
367 if (FindHelper(&pHelperAttributes->guidHelper) != NULL)
368 {
369 DPRINT1("The Helper has already been registered!\n");
370 return 1;
371 }
372
373 pHelper = (PHELPER_ENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELPER_ENTRY));
374 if (pHelper == NULL)
375 {
376 dwError = ERROR_OUTOFMEMORY;
377 goto done;
378 }
379
380 CopyMemory(&pHelper->Attributes, pHelperAttributes, sizeof(NS_HELPER_ATTRIBUTES));
381 pHelper->pDllEntry = pCurrentDll;
382 DPRINT("pHelper->pDllEntry: %p\n", pHelper->pDllEntry);
383
384 if (pguidParentHelper == NULL)
385 {
386 if (pHelperListTail == NULL)
387 {
388 pHelperListHead = pHelper;
389 pHelperListTail = pHelper;
390 }
391 else
392 {
393 pHelper->pNext = pHelperListHead;
394 pHelperListHead->pPrev = pHelper;
395 pHelperListHead = pHelper;
396 }
397 }
398 else
399 {
400 pParentHelper = FindHelper(&pHelperAttributes->guidHelper);
401 if (pParentHelper == NULL)
402 return ERROR_INVALID_PARAMETER;
403
404 if (pParentHelper->pSubHelperHead == NULL && pParentHelper->pSubHelperTail == NULL)
405 {
406 pParentHelper->pSubHelperHead = pHelper;
407 pParentHelper->pSubHelperTail = pHelper;
408 }
409 else
410 {
411 pHelper->pPrev = pParentHelper->pSubHelperTail;
412 pParentHelper->pSubHelperTail->pNext = pHelper;
413 pParentHelper->pSubHelperTail = pHelper;
414 }
415 }
416
417 done:
418
419 return dwError;
420 }
421
422
423 DWORD
424 WINAPI
AddHelperCommand(LPCWSTR pwszMachine,LPWSTR * ppwcArguments,DWORD dwCurrentIndex,DWORD dwArgCount,DWORD dwFlags,LPCVOID pvData,BOOL * pbDone)425 AddHelperCommand(
426 LPCWSTR pwszMachine,
427 LPWSTR *ppwcArguments,
428 DWORD dwCurrentIndex,
429 DWORD dwArgCount,
430 DWORD dwFlags,
431 LPCVOID pvData,
432 BOOL *pbDone)
433 {
434 DWORD dwError = ERROR_SUCCESS;
435
436 DPRINT("AddHelperCommand()\n");
437
438 if (dwArgCount == 2)
439 {
440 // ConResPrintf(StdErr, IDS_INVALID_SYNTAX);
441 // ConResPrintf(StdErr, IDS_HLP_ADD_HELPER_EX);
442 return 1;
443 }
444
445 dwError = LoadHelperDll(ppwcArguments[2], TRUE);
446 if (dwError != ERROR_SUCCESS)
447 return dwError;
448
449 StartHelpers();
450
451 return ERROR_SUCCESS;
452 }
453
454
455 DWORD
456 WINAPI
DeleteHelperCommand(LPCWSTR pwszMachine,LPWSTR * ppwcArguments,DWORD dwCurrentIndex,DWORD dwArgCount,DWORD dwFlags,LPCVOID pvData,BOOL * pbDone)457 DeleteHelperCommand(
458 LPCWSTR pwszMachine,
459 LPWSTR *ppwcArguments,
460 DWORD dwCurrentIndex,
461 DWORD dwArgCount,
462 DWORD dwFlags,
463 LPCVOID pvData,
464 BOOL *pbDone)
465 {
466 PDLL_LIST_ENTRY pEntry;
467 HKEY hKey;
468 DWORD dwError;
469
470 DPRINT("DeleteHelper()\n");
471
472 if (dwArgCount == 2)
473 {
474 // ConResPrintf(StdErr, IDS_INVALID_SYNTAX);
475 // ConResPrintf(StdErr, IDS_HLP_DEL_HELPER_EX);
476 return 1;
477 }
478
479 pEntry = pDllListHead;
480 while (pEntry != NULL)
481 {
482 if (wcscmp(pEntry->pszShortName, ppwcArguments[2]) == 0)
483 {
484 DPRINT1("remove %S\n", pEntry->pszShortName);
485
486 if (pEntry->pPrev != NULL)
487 pEntry->pPrev->pNext = pEntry->pNext;
488 if (pEntry->pNext != NULL)
489 pEntry->pNext->pPrev = pEntry->pPrev;
490 if (pDllListTail == pEntry)
491 pDllListTail = pEntry->pPrev;
492 if (pDllListHead == pEntry)
493 pDllListHead = pEntry->pNext;
494 pEntry->pPrev = NULL;
495 pEntry->pNext = NULL;
496
497 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
498 REG_NETSH_PATH,
499 0,
500 KEY_WRITE,
501 &hKey);
502 if (dwError == ERROR_SUCCESS)
503 {
504 RegDeleteValue(hKey, pEntry->pszValueName);
505 RegCloseKey(hKey);
506 }
507
508 FreeHelperDll(pEntry);
509
510 return 1;
511 }
512
513 pEntry = pEntry->pNext;
514 }
515
516 return ERROR_SUCCESS;
517 }
518
519
520 static
521 VOID
PrintSubContext(_In_ PCONTEXT_ENTRY pParentContext,_In_ DWORD dwLevel)522 PrintSubContext(
523 _In_ PCONTEXT_ENTRY pParentContext,
524 _In_ DWORD dwLevel)
525 {
526 PCONTEXT_ENTRY pContext;
527 PHELPER_ENTRY pHelper;
528 WCHAR szPrefix[22];
529 DWORD i;
530
531 if (pParentContext == NULL)
532 return;
533
534 pContext = pParentContext->pSubContextHead;
535 while (pContext != NULL)
536 {
537 pHelper = FindHelper(&pContext->Guid);
538 if (pHelper != NULL)
539 {
540 if (dwLevel > 10)
541 dwLevel = 10;
542
543 for (i = 0; i < dwLevel * 2; i++)
544 szPrefix[i] = L' ';
545 szPrefix[i] = UNICODE_NULL;
546
547 ConPrintf(StdOut, L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} %-16s %s%s\n",
548 pHelper->Attributes.guidHelper.Data1,
549 pHelper->Attributes.guidHelper.Data2,
550 pHelper->Attributes.guidHelper.Data3,
551 pHelper->Attributes.guidHelper.Data4[0],
552 pHelper->Attributes.guidHelper.Data4[1],
553 pHelper->Attributes.guidHelper.Data4[2],
554 pHelper->Attributes.guidHelper.Data4[3],
555 pHelper->Attributes.guidHelper.Data4[4],
556 pHelper->Attributes.guidHelper.Data4[5],
557 pHelper->Attributes.guidHelper.Data4[6],
558 pHelper->Attributes.guidHelper.Data4[7],
559 pHelper->pDllEntry->pszShortName,
560 szPrefix,
561 pContext->pszContextName);
562 }
563
564 PrintSubContext(pContext, dwLevel + 1);
565
566 pContext = pContext->pNext;
567 }
568 }
569
570
571 DWORD
572 WINAPI
ShowHelperCommand(LPCWSTR pwszMachine,LPWSTR * ppwcArguments,DWORD dwCurrentIndex,DWORD dwArgCount,DWORD dwFlags,LPCVOID pvData,BOOL * pbDone)573 ShowHelperCommand(
574 LPCWSTR pwszMachine,
575 LPWSTR *ppwcArguments,
576 DWORD dwCurrentIndex,
577 DWORD dwArgCount,
578 DWORD dwFlags,
579 LPCVOID pvData,
580 BOOL *pbDone)
581 {
582 DPRINT("ShowHelperCommand()\n");
583
584 ConPrintf(StdOut, L"Helper GUID DLL Name Command\n");
585 ConPrintf(StdOut, L"-------------------------------------- ---------------- --------\n");
586
587 if (pRootContext == NULL)
588 return ERROR_SUCCESS;
589
590 PrintSubContext(pRootContext, 0);
591
592 return ERROR_SUCCESS;
593 }
594