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 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 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 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 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 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 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 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 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 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 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 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 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