Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2612 lines
66 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. routing\netsh\shell\shell.c
  5. Abstract:
  6. The command shell.
  7. Revision History:
  8. Anand Mahalingam 7/6/98 Created
  9. Dave Thaler 99 Updated
  10. --*/
  11. #include "precomp.h"
  12. #undef EXTRA_DEBUG
  13. //
  14. // Define this when we allow a -r option to do remote config
  15. //
  16. #define ALLOW_REMOTES
  17. #define DEFAULT_STARTUP_CONTEXT L"netsh"
  18. WCHAR RtmonPrompt[MAX_CMD_LEN];
  19. WCHAR g_pwszContext[MAX_CMD_LEN] = DEFAULT_STARTUP_CONTEXT;
  20. WCHAR g_pwszNewContext[MAX_CMD_LEN] = DEFAULT_STARTUP_CONTEXT;
  21. LPWSTR g_pwszRouterName = NULL;
  22. LPWSTR g_pwszRememberedConnection = NULL;
  23. HANDLE g_hModule;
  24. BOOL g_bVerbose = FALSE;
  25. BOOL g_bInteractive = FALSE;
  26. DWORD g_dwContextArgCount;
  27. DWORD g_dwTotalArgCount;
  28. BOOL g_bDone = FALSE;
  29. HANDLE g_hLogFile = NULL;
  30. BOOL
  31. WINAPI
  32. HandlerRoutine(
  33. DWORD dwCtrlType // control signal type
  34. );
  35. //
  36. // If quiet, "Ok" and other informational messages will be suppressed.
  37. //
  38. BOOL g_bQuiet = TRUE;
  39. CMD_ENTRY g_UbiqCmds[] =
  40. {
  41. CREATE_CMD_ENTRY( DUMP, HandleUbiqDump),
  42. CREATE_CMD_ENTRY( HELP1, HandleUbiqHelp),
  43. CREATE_CMD_ENTRY( HELP2, HandleUbiqHelp),
  44. };
  45. ULONG g_ulNumUbiqCmds = sizeof(g_UbiqCmds)/sizeof(CMD_ENTRY);
  46. CMD_ENTRY g_ShellCmds[] =
  47. {
  48. // CREATE_CMD_ENTRY( DUMP, HandleShellDump),
  49. // CREATE_CMD_ENTRY( HELP1, HandleShellHelp),
  50. // CREATE_CMD_ENTRY( HELP2, HandleShellHelp),
  51. CREATE_CMD_ENTRY( LOAD, HandleShellLoad),
  52. CREATE_CMD_ENTRY_EX(QUIT, HandleShellExit, CMD_FLAG_INTERACTIVE),
  53. CREATE_CMD_ENTRY_EX(BYE, HandleShellExit, CMD_FLAG_INTERACTIVE),
  54. CREATE_CMD_ENTRY_EX(EXIT, HandleShellExit, CMD_FLAG_INTERACTIVE),
  55. CREATE_CMD_ENTRY_EX(FLUSH, HandleShellFlush, CMD_FLAG_INTERACTIVE),
  56. CREATE_CMD_ENTRY_EX(SAVE, HandleShellSave, CMD_FLAG_INTERACTIVE),
  57. CREATE_CMD_ENTRY_EX(COMMIT, HandleShellCommit, CMD_FLAG_INTERACTIVE),
  58. CREATE_CMD_ENTRY_EX(UNCOMMIT, HandleShellUncommit,CMD_FLAG_INTERACTIVE),
  59. CREATE_CMD_ENTRY_EX(ALIAS, HandleShellAlias, CMD_FLAG_INTERACTIVE),
  60. CREATE_CMD_ENTRY_EX(UNALIAS, HandleShellUnalias, CMD_FLAG_INTERACTIVE),
  61. CREATE_CMD_ENTRY_EX(UPLEVEL, HandleShellUplevel, CMD_FLAG_INTERACTIVE),
  62. CREATE_CMD_ENTRY_EX(PUSHD, HandleShellPushd, CMD_FLAG_INTERACTIVE),
  63. CREATE_CMD_ENTRY_EX(POPD, HandleShellPopd, CMD_FLAG_INTERACTIVE),
  64. };
  65. ULONG g_ulNumShellCmds = sizeof(g_ShellCmds)/sizeof(CMD_ENTRY);
  66. CMD_ENTRY g_ShellAddCmdTable[] = {
  67. CREATE_CMD_ENTRY_EX(ADD_HELPER, HandleAddHelper, CMD_FLAG_LOCAL),
  68. };
  69. CMD_ENTRY g_ShellSetCmdTable[] = {
  70. CREATE_CMD_ENTRY_EX(SET_MACHINE, HandleSetMachine,CMD_FLAG_ONLINE),
  71. CREATE_CMD_ENTRY_EX(SET_MODE, HandleSetMode, CMD_FLAG_INTERACTIVE),
  72. CREATE_CMD_ENTRY_EX(SET_FILE, HandleSetFile, CMD_FLAG_INTERACTIVE),
  73. };
  74. CMD_ENTRY g_ShellDelCmdTable[] = {
  75. CREATE_CMD_ENTRY_EX(DEL_HELPER, HandleDelHelper, CMD_FLAG_LOCAL),
  76. };
  77. CMD_ENTRY g_ShellShowCmdTable[] = {
  78. CREATE_CMD_ENTRY_EX(SHOW_ALIAS, HandleShowAlias, 0),
  79. CREATE_CMD_ENTRY_EX(SHOW_HELPER, HandleShowHelper, 0),
  80. CREATE_CMD_ENTRY_EX(SHOW_MODE, HandleShowMode, CMD_FLAG_INTERACTIVE),
  81. };
  82. CMD_GROUP_ENTRY g_ShellCmdGroups[] =
  83. {
  84. CREATE_CMD_GROUP_ENTRY(GROUP_ADD, g_ShellAddCmdTable),
  85. CREATE_CMD_GROUP_ENTRY(GROUP_DELETE, g_ShellDelCmdTable),
  86. CREATE_CMD_GROUP_ENTRY(GROUP_SET, g_ShellSetCmdTable),
  87. CREATE_CMD_GROUP_ENTRY(GROUP_SHOW, g_ShellShowCmdTable),
  88. };
  89. ULONG g_ulNumGroups = sizeof(g_ShellCmdGroups)/sizeof(CMD_GROUP_ENTRY);
  90. DWORD
  91. ParseCommand(
  92. IN PLIST_ENTRY pleEntry,
  93. IN BOOL bAlias
  94. )
  95. /*++
  96. Routine Description:
  97. This converts any multi-token arguments into separate arg entries.
  98. If bAlias is set, it also expands any args which are aliases.
  99. Arguments:
  100. ple - Pointer to the argument.
  101. bAlias - To look for alias or not.
  102. Called by: ConvertBufferToArgList(), ProcessCommand()
  103. Return Value:
  104. ERROR_NOT_ENOUGH_MEMORY, NO_ERROR
  105. --*/
  106. {
  107. DWORD dwErr = NO_ERROR, dwLen , i;
  108. LPWSTR pw1, pw2, pwszAlias;
  109. PLIST_ENTRY ple, ple1, pleTmp, plePrev, pleAlias;
  110. PARG_ENTRY pae, paeArg;
  111. WCHAR wcTmp;
  112. paeArg = CONTAINING_RECORD(pleEntry, ARG_ENTRY, le);
  113. if (! paeArg->pwszArg)
  114. {
  115. return NO_ERROR;
  116. }
  117. pw1 = paeArg->pwszArg;
  118. //
  119. // Get each argument in the command. Argument within " must
  120. // be retained as is. The token delimiters are ' ' and '='
  121. //
  122. for (plePrev = pleEntry ; ; )
  123. {
  124. // Skip leading whitespace
  125. for(; *pw1 && *pw1 != L'#' && (*pw1 == L' ' || *pw1 == L'\t'); pw1++);
  126. // If it starts with a #, it's the same as an empty string
  127. if (*pw1 == L'#')
  128. *pw1 = L'\0';
  129. // If it's an empty string, we're done
  130. if (!(*pw1))
  131. {
  132. break;
  133. }
  134. if (*pw1 is L'"')
  135. {
  136. for (pw2 = pw1 + 1; *pw2 && *pw2 != L'"'; pw2++);
  137. if (*pw2)
  138. {
  139. pw2++;
  140. }
  141. }
  142. else if (*pw1 is L'=')
  143. {
  144. pw2 = pw1 + 1;
  145. }
  146. else
  147. {
  148. for(pw2 = pw1 + 1; *pw2 && *pw2 != L' ' && *pw2 != L'=' ; pw2++);
  149. }
  150. //
  151. // Add the new argument to the list.
  152. //
  153. pae = MALLOC(sizeof(ARG_ENTRY));
  154. if (pae is NULL)
  155. {
  156. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  157. break;
  158. }
  159. ple = &(pae->le);
  160. ple->Flink = plePrev->Flink;
  161. ple->Blink = plePrev;
  162. plePrev->Flink = ple;
  163. ple->Flink->Blink = ple;
  164. plePrev = ple;
  165. wcTmp = *pw2;
  166. *pw2 = L'\0';
  167. //
  168. // The argument could be an alias. If so replace it by
  169. // the original string.
  170. //
  171. if (bAlias)
  172. {
  173. ATLookupAliasTable(pw1, &pwszAlias);
  174. }
  175. else
  176. {
  177. pwszAlias = NULL;
  178. }
  179. if (pwszAlias)
  180. {
  181. pw1 = pwszAlias;
  182. dwLen = wcslen(pwszAlias) + 1;
  183. }
  184. else
  185. {
  186. dwLen = (DWORD)(pw2 - pw1 + 1);
  187. }
  188. pae->pwszArg = MALLOC(dwLen * sizeof(WCHAR));
  189. if (pae->pwszArg is NULL)
  190. {
  191. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  192. break;
  193. }
  194. // Convert /? and -? to just ?
  195. if (!wcscmp(pw1, L"/?") or !wcscmp(pw1, L"-?"))
  196. {
  197. pw1++;
  198. }
  199. wcscpy(pae->pwszArg, pw1);
  200. *pw2 = wcTmp;
  201. pw1 = pw2;
  202. }
  203. if (dwErr is NO_ERROR)
  204. {
  205. // Free the argument
  206. FREE(paeArg->pwszArg);
  207. pleEntry->Blink->Flink = pleEntry->Flink;
  208. pleEntry->Flink->Blink = pleEntry->Blink;
  209. FREE(paeArg);
  210. }
  211. return dwErr;
  212. }
  213. DWORD
  214. WINAPI
  215. UpdateNewContext(
  216. IN OUT LPWSTR pwszBuffer,
  217. IN LPCWSTR pwszNewToken,
  218. IN DWORD dwArgs
  219. )
  220. /*++
  221. pwszBuffer - a static buffer (should be g_pwszNewContext)
  222. currently this can't be dynamic since the context buffer
  223. would have to be an IN/OUT parameter to this function
  224. and hence to all monitor Entry points.
  225. --*/
  226. {
  227. DWORD dwErr;
  228. PLIST_ENTRY pleHead, pleNode;
  229. PARG_ENTRY pae;
  230. // Convert buffer to list
  231. dwErr = ConvertBufferToArgList( &pleHead, pwszBuffer );
  232. if (dwErr)
  233. {
  234. return dwErr;
  235. }
  236. // Locate in list
  237. for (pleNode = pleHead->Blink; dwArgs>1; pleNode=pleNode->Blink)
  238. {
  239. if (pleNode->Blink isnot pleHead)
  240. {
  241. pae = CONTAINING_RECORD(pleNode->Blink, ARG_ENTRY, le);
  242. if (!wcscmp(pae->pwszArg,L"="))
  243. {
  244. pleNode=pleNode->Blink; // back up over =
  245. if (pleNode->Blink isnot pleHead)
  246. {
  247. pleNode=pleNode->Blink; // back up over tag too
  248. }
  249. }
  250. }
  251. dwArgs--;
  252. }
  253. // Update in list
  254. pae = CONTAINING_RECORD(pleNode, ARG_ENTRY, le);
  255. if (pae->pwszArg)
  256. {
  257. FREE(pae->pwszArg);
  258. }
  259. pae->pwszArg = MALLOC((wcslen(pwszNewToken)+1) * sizeof(WCHAR));
  260. if (pae->pwszArg is NULL)
  261. {
  262. return ERROR_NOT_ENOUGH_MEMORY;
  263. }
  264. wcscpy(pae->pwszArg, pwszNewToken);
  265. // Convert list to buffer
  266. dwErr = ConvertArgListToBuffer( pleHead, pwszBuffer );
  267. return dwErr;
  268. }
  269. DWORD
  270. GetNewContext(
  271. IN LPCWSTR pwszArgument,
  272. OUT LPWSTR *ppwszNewContext,
  273. OUT BOOL *pbContext
  274. )
  275. /*++
  276. Routine Description:
  277. Based on the first command argument and the current context,
  278. determines the context for the new command.
  279. Arguments:
  280. pwszArgument - First argument in the command line.
  281. ppwszNewContext - Pointer to the new context.
  282. pbContext - Is it a new context ?
  283. Return Value:
  284. ERROR_NOT_ENOUGH_MEMORY, NO_ERROR
  285. --*/
  286. {
  287. LPWSTR pwszNewContext, pwcToken, pw1, pwszArgumentCopy, pwszArgumentPtr;
  288. DWORD dwSize;
  289. pwszArgumentCopy = _wcsdup(pwszArgument);
  290. if ( pwszArgumentCopy is NULL )
  291. {
  292. *pbContext = FALSE;
  293. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  294. return ERROR_NOT_ENOUGH_MEMORY;
  295. }
  296. pwszArgumentPtr = pwszArgumentCopy;
  297. //
  298. // New Context cannot be longer than the combined lengths
  299. // of pwszArgument and g_pwszContext.
  300. //
  301. dwSize = wcslen(pwszArgumentCopy) + wcslen(g_pwszContext) + 2;
  302. pwszNewContext = MALLOC(dwSize * sizeof(WCHAR));
  303. if (pwszNewContext is NULL)
  304. {
  305. *pbContext = FALSE;
  306. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  307. free(pwszArgumentPtr);
  308. return ERROR_NOT_ENOUGH_MEMORY;
  309. }
  310. if (pwszArgumentCopy[0] is L'\\')
  311. {
  312. //
  313. // The context is an absolute one.
  314. //
  315. pwszNewContext[0] = L'\0';
  316. pwszArgumentCopy++;
  317. *pbContext = TRUE;
  318. }
  319. else
  320. {
  321. //
  322. // Context is relative to current.
  323. //
  324. wcscpy(pwszNewContext,g_pwszContext);
  325. }
  326. if ((pwcToken = wcstok(pwszArgumentCopy, L"\\" )) is NULL)
  327. {
  328. *ppwszNewContext = pwszNewContext;
  329. free(pwszArgumentPtr);
  330. return NO_ERROR;
  331. }
  332. do
  333. {
  334. if (_wcsicmp(pwcToken, L"..") == 0)
  335. {
  336. //
  337. // Go back one level. If already at root, ignore.
  338. //
  339. if (_wcsicmp(pwszNewContext,L"\\") == 0)
  340. {
  341. }
  342. else
  343. {
  344. pw1 = wcsrchr(pwszNewContext,L'\\');
  345. if (pw1)
  346. {
  347. *pw1 = L'\0';
  348. }
  349. }
  350. *pbContext = TRUE;
  351. }
  352. else
  353. {
  354. //
  355. // add this level to context
  356. //
  357. wcscat(pwszNewContext,L"\\");
  358. wcscat(pwszNewContext,pwcToken);
  359. *pbContext = TRUE;
  360. }
  361. } while ((pwcToken = wcstok((LPWSTR)NULL, L"\\" )) != NULL);
  362. *ppwszNewContext = pwszNewContext;
  363. free(pwszArgumentPtr);
  364. return NO_ERROR;
  365. }
  366. DWORD
  367. AppendString(
  368. IN OUT LPWSTR *ppwszBuffer,
  369. IN LPCWSTR pwszString
  370. )
  371. {
  372. LPWSTR pwszNewBuffer;
  373. DWORD dwLen;
  374. if (*ppwszBuffer is NULL) {
  375. dwLen = wcslen(pwszString) + 1;
  376. pwszNewBuffer = MALLOC( dwLen * sizeof(WCHAR));
  377. if (pwszNewBuffer) {
  378. pwszNewBuffer[0] = 0;
  379. }
  380. } else {
  381. dwLen = wcslen(*ppwszBuffer) + wcslen(pwszString) + 1;
  382. pwszNewBuffer = REALLOC( *ppwszBuffer, dwLen * sizeof(WCHAR));
  383. }
  384. if (!pwszNewBuffer)
  385. {
  386. return ERROR_NOT_ENOUGH_MEMORY;
  387. }
  388. *ppwszBuffer = pwszNewBuffer;
  389. wcscat(pwszNewBuffer, pwszString);
  390. return NO_ERROR;
  391. }
  392. VOID
  393. ConvertArgArrayToBuffer(
  394. IN DWORD dwArgCount,
  395. IN LPCWSTR *argv,
  396. OUT LPWSTR *ppwszBuffer
  397. )
  398. {
  399. DWORD i;
  400. #ifdef EXTRA_DEBUG
  401. PRINT1("In ConvertArgArrayToBuffer:");
  402. for( i = 0; i < dwArgCount; i++)
  403. {
  404. PRINT(argv[i]);
  405. }
  406. #endif
  407. // Initial string to empty
  408. *ppwszBuffer = NULL;
  409. for (i=0; i<dwArgCount; i++)
  410. {
  411. if (i)
  412. {
  413. AppendString(ppwszBuffer, L" ");
  414. }
  415. if (wcschr(argv[i], L' '))
  416. {
  417. AppendString(ppwszBuffer, L"\"");
  418. AppendString(ppwszBuffer, argv[i]);
  419. AppendString(ppwszBuffer, L"\"");
  420. }
  421. else
  422. {
  423. AppendString(ppwszBuffer, argv[i]);
  424. }
  425. }
  426. #ifdef EXTRA_DEBUG
  427. PRINT1("At end of ConvertArgArrayToBuffer:");
  428. PRINT(*ppwszBuffer);
  429. #endif
  430. }
  431. VOID
  432. SetContext(
  433. IN LPCWSTR wszNewContext
  434. )
  435. {
  436. wcscpy(g_pwszContext, wszNewContext);
  437. _wcslwr(g_pwszContext);
  438. }
  439. BOOL
  440. IsImmediate(
  441. IN DWORD dwCmdFlags,
  442. IN DWORD dwRemainingArgs
  443. )
  444. /*++
  445. Description:
  446. Determines whether a command was "immediate". A command is immediate
  447. if the context in which it exists was the current context in the
  448. shell.
  449. Returns:
  450. TRUE if command is "immediate", FALSE if not
  451. --*/
  452. {
  453. if (!(dwCmdFlags & CMD_FLAG_PRIVATE))
  454. {
  455. return FALSE;
  456. }
  457. // One way to tell is to get the current context arg count,
  458. // the total arg count, and the remaining arg count.
  459. return (g_dwContextArgCount + dwRemainingArgs is g_dwTotalArgCount);
  460. }
  461. DWORD
  462. ProcessHelperCommand2(
  463. IN PCNS_CONTEXT_ATTRIBUTES pContext,
  464. IN DWORD dwArgCount,
  465. IN OUT LPWSTR *argv,
  466. IN DWORD dwDisplayFlags,
  467. OUT BOOL *pbDone
  468. )
  469. {
  470. PNS_CONTEXT_ENTRY_FN pfnEntryPt;
  471. DWORD dwRes, dwIdx;
  472. LPWSTR pwszNewContext = NULL;
  473. LPWSTR pwszOrigContext = NULL;
  474. if (pContext->dwFlags & ~dwDisplayFlags)
  475. {
  476. return ERROR_CMD_NOT_FOUND;
  477. }
  478. pfnEntryPt = (!pContext->pReserved) ? NULL : ((PNS_PRIV_CONTEXT_ATTRIBUTES)pContext->pReserved)->pfnEntryFn;
  479. // If arg was abbreviated, replace argv[0] with expanded name
  480. if (wcscmp(argv[0], pContext->pwszContext))
  481. {
  482. pwszOrigContext = argv[0];
  483. argv[0] = pContext->pwszContext;
  484. }
  485. ConvertArgArrayToBuffer(dwArgCount, argv, &pwszNewContext);
  486. if (pwszNewContext)
  487. {
  488. wcsncpy(g_pwszNewContext, pwszNewContext, MAX_CMD_LEN);
  489. //
  490. // this is something of a hack - we put the NULL 100 chars before the end of the buffer to prevent a buffer overrun later
  491. // in UpdateNewContext: 190933 netsh hit an AV on netsh!._wcsnicmp
  492. //
  493. g_pwszNewContext[ MAX_CMD_LEN - 100 ] = 0;
  494. FREE(pwszNewContext);
  495. pwszNewContext = NULL;
  496. }
  497. //
  498. // Call the entry point of helper.
  499. //
  500. if (pfnEntryPt)
  501. {
  502. dwRes = (*pfnEntryPt)(g_pwszRouterName,
  503. argv, // + 1,
  504. dwArgCount, // - 1,
  505. dwDisplayFlags,
  506. NULL,
  507. g_pwszNewContext);
  508. }
  509. else
  510. {
  511. dwRes = GenericMonitor(pContext,
  512. g_pwszRouterName,
  513. argv, // + 1,
  514. dwArgCount, // - 1,
  515. dwDisplayFlags,
  516. NULL,
  517. g_pwszNewContext);
  518. }
  519. if (pwszOrigContext)
  520. {
  521. argv[0] = pwszOrigContext;
  522. }
  523. if (dwRes isnot NO_ERROR)
  524. {
  525. if (dwRes is ERROR_CONTEXT_SWITCH)
  526. {
  527. if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
  528. {
  529. LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
  530. if (argv2 is NULL)
  531. {
  532. return ERROR_NOT_ENOUGH_MEMORY;
  533. }
  534. CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
  535. argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
  536. if (argv2[dwArgCount] is NULL)
  537. {
  538. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  539. }
  540. else
  541. {
  542. wcscpy(argv2[dwArgCount], CMD_HELP2);
  543. g_dwTotalArgCount = dwArgCount+1;
  544. dwRes = ProcessHelperCommand2(pContext,
  545. dwArgCount+1,
  546. argv2,
  547. dwDisplayFlags,
  548. pbDone);
  549. FREE(argv2[dwArgCount]);
  550. }
  551. FREE(argv2);
  552. return dwRes;
  553. }
  554. //
  555. // A context switch.
  556. //
  557. SetContext(g_pwszNewContext);
  558. dwRes = NO_ERROR;
  559. }
  560. else if (dwRes is ERROR_CONNECT_REMOTE_CONFIG)
  561. {
  562. PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
  563. g_pwszRouterName);
  564. *pbDone = TRUE;
  565. }
  566. }
  567. return dwRes;
  568. }
  569. DWORD
  570. WINAPI
  571. ProcessHelperCommand(
  572. IN DWORD dwArgCount,
  573. IN OUT LPWSTR *argv,
  574. IN DWORD dwDisplayFlags,
  575. // OUT LPWSTR *ppwszNewContext,
  576. OUT BOOL *pbDone
  577. )
  578. {
  579. PCNS_CONTEXT_ATTRIBUTES pContext;
  580. PNS_CONTEXT_ENTRY_FN pfnEntryPt;
  581. DWORD dwRes, dwIdx;
  582. LPWSTR pwszNewContext = NULL;
  583. LPWSTR pwszOrigContext = NULL;
  584. PNS_HELPER_TABLE_ENTRY pHelper;
  585. dwRes = GetRootContext( &pContext, &pHelper);
  586. if (dwRes)
  587. {
  588. return dwRes;
  589. }
  590. dwRes = GetContextEntry(pHelper, argv[0], &pContext);
  591. if (dwRes isnot NO_ERROR)
  592. {
  593. return ERROR_CMD_NOT_FOUND;
  594. }
  595. if (pContext->dwFlags & ~dwDisplayFlags)
  596. {
  597. return ERROR_CMD_NOT_FOUND;
  598. }
  599. #if 1
  600. pfnEntryPt = (!pContext->pReserved) ? NULL : ((PNS_PRIV_CONTEXT_ATTRIBUTES)pContext->pReserved)->pfnEntryFn;
  601. #else
  602. dwRes = GetHelperAttributes(dwIdx, &pfnEntryPt);
  603. if (dwRes != NO_ERROR)
  604. {
  605. //
  606. // Could not find helper or could not load the DLL
  607. //
  608. return dwRes;
  609. }
  610. #endif
  611. // If arg was abbreviated, replace argv[0] with expanded name
  612. if (wcscmp(argv[0], pContext->pwszContext))
  613. {
  614. pwszOrigContext = argv[0];
  615. argv[0] = pContext->pwszContext;
  616. }
  617. ConvertArgArrayToBuffer(dwArgCount, argv, &pwszNewContext);
  618. if (pwszNewContext)
  619. {
  620. wcsncpy(g_pwszNewContext, pwszNewContext, MAX_CMD_LEN);
  621. g_pwszNewContext[ MAX_CMD_LEN - 1 ] = '\0';
  622. FREE(pwszNewContext);
  623. pwszNewContext = NULL;
  624. }
  625. //
  626. // Call the entry point of helper.
  627. //
  628. if (pfnEntryPt)
  629. {
  630. dwRes = (*pfnEntryPt)(g_pwszRouterName,
  631. argv + 1,
  632. dwArgCount - 1,
  633. dwDisplayFlags,
  634. NULL,
  635. g_pwszNewContext);
  636. }
  637. else
  638. {
  639. dwRes = GenericMonitor(pContext,
  640. g_pwszRouterName,
  641. argv + 1,
  642. dwArgCount - 1,
  643. dwDisplayFlags,
  644. NULL,
  645. g_pwszNewContext);
  646. }
  647. if (pwszOrigContext)
  648. {
  649. argv[0] = pwszOrigContext;
  650. }
  651. if (dwRes isnot NO_ERROR)
  652. {
  653. if (dwRes is ERROR_CONTEXT_SWITCH)
  654. {
  655. if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
  656. {
  657. LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
  658. if (argv2 is NULL)
  659. {
  660. return ERROR_NOT_ENOUGH_MEMORY;
  661. }
  662. CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
  663. argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
  664. if (argv2[dwArgCount] is NULL)
  665. {
  666. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  667. }
  668. else
  669. {
  670. wcscpy(argv2[dwArgCount], CMD_HELP2);
  671. g_dwTotalArgCount = dwArgCount+1;
  672. dwRes = ProcessHelperCommand(dwArgCount+1,
  673. argv2,
  674. dwDisplayFlags,
  675. pbDone);
  676. FREE(argv2[dwArgCount]);
  677. }
  678. FREE(argv2);
  679. return dwRes;
  680. }
  681. //
  682. // A context switch.
  683. //
  684. SetContext(g_pwszNewContext);
  685. dwRes = NO_ERROR;
  686. }
  687. else if (dwRes is ERROR_CONNECT_REMOTE_CONFIG)
  688. {
  689. PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
  690. g_pwszRouterName);
  691. *pbDone = TRUE;
  692. }
  693. }
  694. return dwRes;
  695. }
  696. DWORD
  697. WINAPI
  698. ExecuteHandler(
  699. IN HANDLE hModule,
  700. IN CMD_ENTRY *pCmdEntry,
  701. IN OUT LPWSTR *argv,
  702. IN DWORD dwNumMatched,
  703. IN DWORD dwArgCount,
  704. IN DWORD dwFlags,
  705. IN LPCVOID pvData,
  706. IN LPCWSTR pwszGroupName,
  707. OUT BOOL *pbDone)
  708. {
  709. DWORD dwErr = NO_ERROR;
  710. if (((dwArgCount - dwNumMatched) == 1)
  711. && IsHelpToken(argv[dwNumMatched]))
  712. {
  713. dwErr = ERROR_SHOW_USAGE;
  714. }
  715. else
  716. {
  717. //
  718. // Call the parsing routine for the command
  719. //
  720. dwErr = pCmdEntry->pfnCmdHandler( g_pwszRouterName,
  721. argv,
  722. dwNumMatched,
  723. dwArgCount,
  724. dwFlags,
  725. pvData,
  726. pbDone );
  727. }
  728. if (dwErr is ERROR_INVALID_SYNTAX)
  729. {
  730. PrintError(NULL, dwErr);
  731. dwErr = ERROR_SHOW_USAGE;
  732. }
  733. switch (dwErr) {
  734. case ERROR_SHOW_USAGE:
  735. //
  736. // If the only argument is a help token, just
  737. // display the help.
  738. //
  739. if (NULL != pwszGroupName)
  740. {
  741. LPWSTR pwszGroupFullCmd = (LPWSTR)
  742. MALLOC( ( wcslen(pwszGroupName) +
  743. wcslen(pCmdEntry->pwszCmdToken) +
  744. 2 // for blank and NULL characters
  745. ) * sizeof(WCHAR)
  746. );
  747. if (NULL == pwszGroupFullCmd)
  748. {
  749. // we still try to print without group name
  750. PrintMessageFromModule( hModule,
  751. pCmdEntry->dwCmdHlpToken,
  752. pCmdEntry->pwszCmdToken );
  753. }
  754. else
  755. {
  756. wcscpy(pwszGroupFullCmd, pwszGroupName);
  757. wcscat(pwszGroupFullCmd, L" ");
  758. wcscat(pwszGroupFullCmd, pCmdEntry->pwszCmdToken);
  759. PrintMessageFromModule( hModule,
  760. pCmdEntry->dwCmdHlpToken,
  761. pwszGroupFullCmd );
  762. FREE(pwszGroupFullCmd);
  763. }
  764. }
  765. else
  766. {
  767. PrintMessageFromModule( hModule,
  768. pCmdEntry->dwCmdHlpToken,
  769. pCmdEntry->pwszCmdToken );
  770. }
  771. dwErr = NO_ERROR;
  772. break;
  773. case NO_ERROR:
  774. case ERROR_SUPPRESS_OUTPUT:
  775. break;
  776. case ERROR_OKAY:
  777. if (!g_bQuiet)
  778. {
  779. PrintMessageFromModule( NULL, MSG_OKAY);
  780. }
  781. dwErr = NO_ERROR;
  782. break;
  783. default:
  784. PrintError(NULL, dwErr);
  785. break;
  786. }
  787. if (!g_bQuiet)
  788. {
  789. PrintMessage( MSG_NEWLINE );
  790. }
  791. return dwErr;
  792. }
  793. BOOL
  794. ProcessGroupCommand(
  795. IN DWORD dwArgCount,
  796. IN PTCHAR *argv,
  797. IN DWORD dwDisplayFlags,
  798. OUT BOOL *pbDone
  799. )
  800. {
  801. BOOL bFound = FALSE;
  802. DWORD i, j, dwNumMatched, dwErr;
  803. for(i = 0; i < g_ulNumGroups; i++)
  804. {
  805. if (g_ShellCmdGroups[i].dwFlags & ~dwDisplayFlags)
  806. {
  807. continue;
  808. }
  809. if (MatchToken(argv[0],
  810. g_ShellCmdGroups[i].pwszCmdGroupToken))
  811. {
  812. // See if it's a request for help
  813. if ((dwArgCount < 2) || IsHelpToken(argv[1]))
  814. {
  815. PCNS_CONTEXT_ATTRIBUTES pContext;
  816. dwErr = GetRootContext(&pContext, NULL);
  817. if (dwErr is NO_ERROR)
  818. {
  819. dwErr = DisplayContextHelp(
  820. pContext,
  821. CMD_FLAG_PRIVATE,
  822. dwDisplayFlags,
  823. dwArgCount-2+1,
  824. g_ShellCmdGroups[i].pwszCmdGroupToken );
  825. }
  826. return TRUE;
  827. }
  828. //
  829. // Command matched entry i, so look at the table of sub commands
  830. // for this command
  831. //
  832. for (j = 0; j < g_ShellCmdGroups[i].ulCmdGroupSize; j++)
  833. {
  834. if (g_ShellCmdGroups[i].pCmdGroup[j].dwFlags
  835. & ~dwDisplayFlags)
  836. {
  837. continue;
  838. }
  839. if (MatchCmdLine(argv,
  840. dwArgCount,
  841. g_ShellCmdGroups[i].pCmdGroup[j].pwszCmdToken,
  842. &dwNumMatched))
  843. {
  844. bFound = TRUE;
  845. dwErr = ExecuteHandler(g_hModule,
  846. &g_ShellCmdGroups[i].pCmdGroup[j],
  847. argv, dwNumMatched, dwArgCount,
  848. dwDisplayFlags,
  849. NULL,
  850. g_ShellCmdGroups[i].pwszCmdGroupToken,
  851. pbDone);
  852. //
  853. // quit the for(j)
  854. //
  855. break;
  856. }
  857. }
  858. break;
  859. }
  860. }
  861. return bFound;
  862. }
  863. DWORD
  864. LookupCommandHandler(
  865. IN LPCWSTR pwszCmd
  866. )
  867. {
  868. // Eventually, we want to look up commands in sub-contexts first,
  869. // and end up with the global context. For now, we'll just do global.
  870. DWORD i;
  871. for (i = 0; i < g_ulNumShellCmds; i++)
  872. {
  873. if (MatchToken(pwszCmd, g_ShellCmds[i].pwszCmdToken))
  874. {
  875. return i;
  876. }
  877. }
  878. return -1;
  879. }
  880. VOID
  881. FreeArgArray(
  882. DWORD argc,
  883. LPWSTR *argv
  884. )
  885. {
  886. DWORD i;
  887. for (i = 0; i < argc; i++)
  888. {
  889. FREE(argv[i]);
  890. }
  891. FREE(argv);
  892. }
  893. DWORD
  894. ConvertArgListToBuffer(
  895. IN PLIST_ENTRY pleHead,
  896. OUT LPWSTR pwszBuffer
  897. )
  898. {
  899. PLIST_ENTRY ple;
  900. PARG_ENTRY pae;
  901. LPWSTR p = pwszBuffer;
  902. *p = '\0';
  903. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink )
  904. {
  905. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  906. if (p isnot pwszBuffer)
  907. {
  908. *p++ = ' ';
  909. }
  910. wcscpy(p, pae->pwszArg);
  911. p += wcslen(p);
  912. }
  913. return NO_ERROR;
  914. }
  915. DWORD
  916. AppendArgument(
  917. IN OUT LPWSTR **pargv,
  918. IN DWORD i,
  919. IN LPCWSTR pwszString
  920. )
  921. {
  922. DWORD dwErr;
  923. dwErr = AppendString( &(*pargv)[i], pwszString );
  924. if ((*pargv)[i] is NULL) {
  925. FreeArgArray(i, *pargv);
  926. *pargv = NULL;
  927. return ERROR_NOT_ENOUGH_MEMORY;
  928. }
  929. return NO_ERROR;
  930. }
  931. DWORD
  932. ConvertArgListToArray(
  933. IN PLIST_ENTRY pleContextHead,
  934. IN PLIST_ENTRY pleHead,
  935. OUT PDWORD pargc,
  936. OUT LPWSTR **pargv,
  937. OUT PDWORD pdwContextArgc
  938. )
  939. {
  940. DWORD dwErr = NO_ERROR;
  941. DWORD argc = 0, i = 0;
  942. LPWSTR *argv = NULL, p;
  943. BOOL bEqualTo;
  944. PLIST_ENTRY ple;
  945. PARG_ENTRY pae;
  946. #ifdef EXTRA_DEBUG
  947. if (pleHead)
  948. {
  949. PLIST_ENTRY ple;
  950. PRINT1("In ConvertArgListToArray:");
  951. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  952. {
  953. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  954. PRINT(pae->pwszArg);
  955. }
  956. }
  957. #endif
  958. // Count tokens
  959. if (pleContextHead)
  960. {
  961. for (ple = pleContextHead->Flink; ple != pleContextHead; ple = ple->Flink)
  962. argc++;
  963. }
  964. *pdwContextArgc = argc;
  965. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  966. argc++;
  967. do {
  968. if (!argc)
  969. break;
  970. //
  971. // Allocate space for arguments
  972. //
  973. argv = MALLOC(argc * sizeof(LPCWSTR));
  974. if (argv is NULL)
  975. {
  976. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  977. break;
  978. }
  979. memset(argv, 0, argc * sizeof(LPCWSTR));
  980. bEqualTo = FALSE;
  981. //
  982. // Copy the arguments from the list into an argv kind of
  983. // structure. At this point, the arguments tag, '=' and
  984. // the value are made into one argument tag=value.
  985. //
  986. //
  987. // Copy context
  988. //
  989. i = 0;
  990. if (pleContextHead)
  991. {
  992. for (ple = pleContextHead->Flink;
  993. ple != pleContextHead;
  994. ple = ple->Flink)
  995. {
  996. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  997. dwErr = AppendArgument( &argv, i++, pae->pwszArg );
  998. if ( dwErr isnot NO_ERROR ) {
  999. break;
  1000. }
  1001. }
  1002. }
  1003. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink )
  1004. {
  1005. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1006. //
  1007. // Remove any " from the string name
  1008. //
  1009. if (pae->pwszArg[0] == L'"')
  1010. {
  1011. if (bEqualTo)
  1012. {
  1013. dwErr=AppendArgument(&argv, i-1, pae->pwszArg+1);
  1014. if ( dwErr isnot NO_ERROR ) {
  1015. break;
  1016. }
  1017. bEqualTo = FALSE;
  1018. }
  1019. else
  1020. {
  1021. dwErr=AppendArgument(&argv, i++, pae->pwszArg+1);
  1022. if (dwErr isnot NO_ERROR ) {
  1023. break;
  1024. }
  1025. }
  1026. p = argv[i-1];
  1027. if (p[wcslen(p) - 1] == L'"')
  1028. {
  1029. p[wcslen(p) - 1] = L'\0';
  1030. }
  1031. continue;
  1032. }
  1033. //
  1034. // combine arguments of the form tag = value
  1035. //
  1036. if ((wcscmp(pae->pwszArg,L"=") == 0) || bEqualTo)
  1037. {
  1038. bEqualTo = (bEqualTo) ? FALSE : TRUE;
  1039. if (i > 0)
  1040. {
  1041. i--;
  1042. }
  1043. dwErr = AppendArgument( &argv, i++, pae->pwszArg);
  1044. if (dwErr isnot NO_ERROR ) {
  1045. break;
  1046. }
  1047. }
  1048. else
  1049. {
  1050. dwErr = AppendArgument( &argv, i++, pae->pwszArg);
  1051. if (dwErr isnot NO_ERROR ) {
  1052. break;
  1053. }
  1054. }
  1055. }
  1056. } while (FALSE);
  1057. #ifdef EXTRA_DEBUG
  1058. PRINT1("At end of ConvertArgListToArray:");
  1059. for( i = 0; i < argc; i++)
  1060. {
  1061. PRINT(argv[i]);
  1062. }
  1063. #endif
  1064. *pargc = i;
  1065. *pargv = argv;
  1066. return dwErr;
  1067. }
  1068. DWORD
  1069. ConvertBufferToArgList(
  1070. PLIST_ENTRY *ppleHead,
  1071. LPCWSTR pwszBuffer
  1072. )
  1073. {
  1074. PLIST_ENTRY pleHead = NULL;
  1075. DWORD dwErr = NO_ERROR;
  1076. PARG_ENTRY pae;
  1077. #ifdef EXTRA_DEBUG
  1078. PRINT1("In ConvertBufferToArgList:");
  1079. PRINT(pwszBuffer);
  1080. #endif
  1081. do {
  1082. //
  1083. // First convert the command line to a list of tokens
  1084. //
  1085. pleHead = MALLOC(sizeof(ARG_ENTRY));
  1086. if (pleHead is NULL)
  1087. {
  1088. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1089. break;
  1090. }
  1091. ZeroMemory(pleHead, sizeof(ARG_ENTRY));
  1092. InitializeListHead(pleHead);
  1093. pae = MALLOC(sizeof(ARG_ENTRY));
  1094. if (pae is NULL)
  1095. {
  1096. FREE(pleHead);
  1097. pleHead = NULL;
  1098. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1099. break;
  1100. }
  1101. pae->pwszArg = MALLOC((wcslen(pwszBuffer)+1) * sizeof(WCHAR));
  1102. if (pae->pwszArg is NULL)
  1103. {
  1104. FREE(pleHead);
  1105. FREE(pae);
  1106. pleHead = NULL;
  1107. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1108. break;
  1109. }
  1110. wcscpy(pae->pwszArg, pwszBuffer);
  1111. InsertHeadList(pleHead, &(pae->le));
  1112. dwErr = ParseCommand(pleHead->Flink, FALSE);
  1113. if (dwErr isnot NO_ERROR)
  1114. {
  1115. FREE_ARG_LIST(pleHead);
  1116. pleHead = NULL;
  1117. break;
  1118. }
  1119. } while (FALSE);
  1120. #ifdef EXTRA_DEBUG
  1121. if (pleHead)
  1122. {
  1123. PLIST_ENTRY ple;
  1124. PRINT1("At end of ConvertBufferToArgList:");
  1125. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  1126. {
  1127. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1128. PRINT(pae->pwszArg);
  1129. }
  1130. }
  1131. #endif
  1132. *ppleHead = pleHead;
  1133. if (dwErr is ERROR_NOT_ENOUGH_MEMORY)
  1134. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  1135. return dwErr;
  1136. }
  1137. DWORD
  1138. ProcessShellCommand(
  1139. IN DWORD dwArgCount,
  1140. IN OUT LPWSTR *argv,
  1141. IN DWORD dwDisplayFlags,
  1142. // OUT LPWSTR *ppwszNewContext,
  1143. OUT BOOL *pbDone
  1144. )
  1145. {
  1146. DWORD i;
  1147. for (i = 0; i < g_ulNumShellCmds; i++)
  1148. {
  1149. if (g_ShellCmds[i].dwFlags & ~dwDisplayFlags)
  1150. {
  1151. continue;
  1152. }
  1153. if (MatchToken( argv[0],
  1154. g_ShellCmds[i].pwszCmdToken ))
  1155. {
  1156. return ExecuteHandler( g_hModule,
  1157. &g_ShellCmds[i],
  1158. argv,
  1159. 1,
  1160. dwArgCount,
  1161. dwDisplayFlags,
  1162. NULL,
  1163. NULL,
  1164. pbDone );
  1165. }
  1166. }
  1167. return ERROR_CMD_NOT_FOUND;
  1168. }
  1169. DWORD
  1170. ProcessCommand(
  1171. IN LPCWSTR pwszCmdLine,
  1172. OUT BOOL *pbDone
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. Executes command if it is for the shell or else calls the
  1177. corresponding helper routine.
  1178. Arguments:
  1179. pwszCmdLine - The command line to be executed.
  1180. Return Value:
  1181. TRUE, FALSE - (Whether to quit the program or not)
  1182. --*/
  1183. {
  1184. LPCWSTR pwszAliasString = NULL;
  1185. DWORD dwRes = NO_ERROR, i, dwLen, j;
  1186. WCHAR wszAliasString[MAX_CMD_LEN],
  1187. pwszContext[MAX_CMD_LEN];
  1188. WCHAR pwszCommandLine[MAX_CMD_LEN],*pwszNewContext;
  1189. LPCWSTR pwcAliasString, pw1,pw2,pw3;
  1190. BOOL bContext, bEqualTo, bTmp;
  1191. LPCWSTR pwszArg0, pwszArg1, pwszArg2;
  1192. PLIST_ENTRY ple, ple1, ple2, pleHead, pleTmp, pleNext;
  1193. PLIST_ENTRY pleContextHead;
  1194. PARG_ENTRY pae;
  1195. DWORD dwArgCount = 0, dwContextArgCount = 0;
  1196. LPWSTR *argv, pwcNewContext = NULL;
  1197. BOOL bShellCmd, bAlias, bFound = FALSE, dwDisplayFlags;
  1198. PCNS_CONTEXT_ATTRIBUTES pContext;
  1199. *pbDone = FALSE;
  1200. dwDisplayFlags = (g_bInteractive)? CMD_FLAG_INTERACTIVE : 0;
  1201. dwDisplayFlags |= ~CMD_FLAG_LIMIT_MASK;
  1202. // Command is executed on the local machine if router name is null
  1203. if (!g_pwszRouterName)
  1204. {
  1205. dwDisplayFlags |= CMD_FLAG_LOCAL;
  1206. }
  1207. if (g_bCommit)
  1208. {
  1209. dwDisplayFlags |= CMD_FLAG_ONLINE;
  1210. }
  1211. if (g_bVerbose)
  1212. {
  1213. PrintMessage(L"> %1!s!\n", pwszCmdLine);
  1214. }
  1215. dwRes = ConvertBufferToArgList(&pleContextHead, g_pwszContext);
  1216. if (dwRes isnot NO_ERROR)
  1217. {
  1218. *pbDone = TRUE;
  1219. return dwRes;
  1220. }
  1221. dwRes = ConvertBufferToArgList(&pleHead, pwszCmdLine);
  1222. if (dwRes isnot NO_ERROR)
  1223. {
  1224. FREE_ARG_LIST(pleContextHead);
  1225. *pbDone = TRUE;
  1226. return dwRes;
  1227. }
  1228. if (IsListEmpty(pleHead))
  1229. {
  1230. FREE_ARG_LIST(pleHead);
  1231. FREE_ARG_LIST(pleContextHead);
  1232. return NO_ERROR;
  1233. }
  1234. // Expand alias (not recursive)
  1235. dwRes = ParseCommand(pleHead->Flink, TRUE);
  1236. if (dwRes isnot NO_ERROR)
  1237. {
  1238. FREE_ARG_LIST(pleHead);
  1239. FREE_ARG_LIST(pleContextHead);
  1240. *pbDone = TRUE;
  1241. return dwRes;
  1242. }
  1243. #ifdef EXTRA_DEBUG
  1244. PRINT1("In ProcessCommand 2:");
  1245. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  1246. {
  1247. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1248. PRINT(pae->pwszArg);
  1249. }
  1250. #endif
  1251. // Go through and expand any multi-tokens args into separate args
  1252. for (ple = (pleHead->Flink); ple != pleHead; ple = pleNext)
  1253. {
  1254. pleNext = ple->Flink;
  1255. dwRes = ParseCommand(ple, FALSE);
  1256. if (dwRes isnot NO_ERROR)
  1257. {
  1258. break;
  1259. }
  1260. }
  1261. if (dwRes isnot NO_ERROR)
  1262. {
  1263. FREE_ARG_LIST(pleHead);
  1264. FREE_ARG_LIST(pleContextHead);
  1265. *pbDone = TRUE;
  1266. return dwRes;
  1267. }
  1268. #ifdef EXTRA_DEBUG
  1269. PRINT1("In ProcessCommand 3:");
  1270. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  1271. {
  1272. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1273. PRINT(pae->pwszArg);
  1274. }
  1275. #endif
  1276. //
  1277. // At this point, we should have a fully formed command,
  1278. // hopefully operable within the current context.
  1279. // The first token may be a command. If so, then the args
  1280. // will be the context followed by the rest of the tokens.
  1281. // If the first token is not a command, then the args will
  1282. // be the context followed by all the tokens.
  1283. //
  1284. if (IsListEmpty(pleHead))
  1285. {
  1286. FREE_ARG_LIST(pleHead);
  1287. FREE_ARG_LIST(pleContextHead);
  1288. return NO_ERROR;
  1289. }
  1290. pae = CONTAINING_RECORD(pleHead->Flink, ARG_ENTRY, le);
  1291. pwszArg0 = pae->pwszArg;
  1292. GetRootContext( &g_CurrentContext, &g_CurrentHelper );
  1293. do
  1294. {
  1295. // In the first context (only) we try, private commands are valid.
  1296. dwDisplayFlags |= CMD_FLAG_PRIVATE;
  1297. pContext = g_CurrentContext;
  1298. for(;;)
  1299. {
  1300. dwRes = ConvertArgListToArray( pleContextHead,
  1301. pleHead,
  1302. &dwArgCount,
  1303. &argv,
  1304. &dwContextArgCount );
  1305. g_dwTotalArgCount = dwArgCount;
  1306. g_dwContextArgCount = dwContextArgCount;
  1307. #if 1
  1308. # if 1
  1309. dwRes = ProcessHelperCommand2( pContext,
  1310. dwArgCount,
  1311. argv,
  1312. dwDisplayFlags,
  1313. pbDone );
  1314. # else
  1315. dwRes = GenericMonitor( pContext,
  1316. g_pwszRouterName,
  1317. argv,
  1318. dwArgCount,
  1319. dwDisplayFlags,
  1320. NULL,
  1321. g_pwszNewContext );
  1322. # endif
  1323. #else
  1324. {
  1325. if (!ProcessGroupCommand(dwArgCount, argv, dwDisplayFlags, pbDone))
  1326. {
  1327. //
  1328. // Having got the context and the command, see if there
  1329. // is a helper for it.
  1330. //
  1331. dwRes = ProcessHelperCommand( dwArgCount,
  1332. argv,
  1333. dwDisplayFlags,
  1334. // &pwszNewContext,
  1335. pbDone );
  1336. if (dwRes is ERROR_CMD_NOT_FOUND)
  1337. {
  1338. dwRes = ProcessShellCommand( dwArgCount,
  1339. argv,
  1340. dwDisplayFlags,
  1341. // &pwszNewContext,
  1342. pbDone );
  1343. }
  1344. }
  1345. }
  1346. #endif
  1347. FreeArgArray(dwArgCount, argv);
  1348. if (*pbDone or ((dwRes isnot ERROR_CMD_NOT_FOUND)
  1349. && (dwRes isnot ERROR_CONTINUE_IN_PARENT_CONTEXT)))
  1350. {
  1351. break;
  1352. }
  1353. // Make sure we don't look above "netsh"
  1354. if (pleContextHead->Flink->Flink == pleContextHead)
  1355. {
  1356. break;
  1357. }
  1358. // Delete the last element of the context list
  1359. // (Try inheriting a command from one level up)
  1360. ple = pleContextHead->Blink;
  1361. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1362. if (pae->pwszArg)
  1363. FREE(pae->pwszArg);
  1364. RemoveEntryList(ple);
  1365. FREE(pae);
  1366. GetParentContext(pContext, &pContext);
  1367. dwDisplayFlags &= ~CMD_FLAG_PRIVATE;
  1368. }
  1369. #if 0
  1370. if (pwszNewContext)
  1371. {
  1372. FREE(pwszNewContext);
  1373. pwszNewContext = NULL;
  1374. }
  1375. #endif
  1376. } while (FALSE);
  1377. switch(dwRes)
  1378. {
  1379. case ERROR_OKAY:
  1380. if (!g_bQuiet)
  1381. {
  1382. PrintMessageFromModule(g_hModule, MSG_OKAY);
  1383. }
  1384. break;
  1385. case ERROR_NOT_ENOUGH_MEMORY:
  1386. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  1387. *pbDone = TRUE;
  1388. break;
  1389. case ERROR_CMD_NOT_FOUND:
  1390. {
  1391. LPWSTR pwszCmdLineDup = _wcsdup(pwszCmdLine);
  1392. if (!pwszCmdLineDup)
  1393. {
  1394. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  1395. return ERROR_NOT_ENOUGH_MEMORY;
  1396. }
  1397. if (wcslen(pwszCmdLineDup) > 256)
  1398. {
  1399. wcscpy(pwszCmdLineDup + 250, L"...");
  1400. }
  1401. PrintMessageFromModule(NULL, ERROR_CMD_NOT_FOUND, pwszCmdLineDup);
  1402. free(pwszCmdLineDup);
  1403. }
  1404. break;
  1405. case ERROR_CONTEXT_SWITCH:
  1406. {
  1407. if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
  1408. {
  1409. LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
  1410. if (argv2 is NULL)
  1411. {
  1412. return ERROR_NOT_ENOUGH_MEMORY;
  1413. }
  1414. CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
  1415. argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
  1416. if (argv2[dwArgCount] is NULL)
  1417. {
  1418. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  1419. }
  1420. else
  1421. {
  1422. wcscpy(argv2[dwArgCount], CMD_HELP2);
  1423. g_dwTotalArgCount = dwArgCount+1;
  1424. dwRes = ProcessHelperCommand(dwArgCount+1,
  1425. argv2,
  1426. dwDisplayFlags,
  1427. pbDone);
  1428. FREE(argv2[dwArgCount]);
  1429. }
  1430. FREE(argv2);
  1431. return dwRes;
  1432. }
  1433. //
  1434. // A context switch.
  1435. //
  1436. SetContext(g_pwszNewContext);
  1437. dwRes = NO_ERROR;
  1438. break;
  1439. }
  1440. case ERROR_CONNECT_REMOTE_CONFIG:
  1441. PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
  1442. g_pwszRouterName);
  1443. g_bDone = TRUE;
  1444. break;
  1445. default:
  1446. // We don't want to print out an error in the default case here since one would have
  1447. // printed by ExecuteHandler already. Doing this will cause a duplicate message to
  1448. // be displayed.
  1449. break;
  1450. }
  1451. FREE_ARG_LIST(pleHead);
  1452. FREE_ARG_LIST(pleContextHead);
  1453. return dwRes;
  1454. }
  1455. // Append line to the full command
  1456. DWORD
  1457. AppendLineToCommand(
  1458. LPCWSTR pwszCmdLine,
  1459. DWORD dwCmdLineLen,
  1460. LPWSTR *ppwszFullCommand,
  1461. DWORD *dwFullCommandLen
  1462. )
  1463. {
  1464. LPWSTR pwszNewCommand;
  1465. DWORD dwErr = NO_ERROR;
  1466. DWORD dwLen;
  1467. // Allocate enough space to hold the full command
  1468. dwLen = *dwFullCommandLen + dwCmdLineLen;
  1469. if (*ppwszFullCommand is NULL)
  1470. {
  1471. pwszNewCommand = MALLOC( (dwLen+1) * sizeof(WCHAR) );
  1472. }
  1473. else
  1474. {
  1475. pwszNewCommand = REALLOC(*ppwszFullCommand, (dwLen+1) * sizeof(WCHAR) );
  1476. }
  1477. if (!pwszNewCommand)
  1478. {
  1479. return ERROR_NOT_ENOUGH_MEMORY;
  1480. }
  1481. // Append cmd
  1482. wcscpy(pwszNewCommand + *dwFullCommandLen, pwszCmdLine);
  1483. // Update the pointer
  1484. *ppwszFullCommand = pwszNewCommand;
  1485. *dwFullCommandLen = dwLen;
  1486. return dwErr;
  1487. }
  1488. DWORD
  1489. MainCommandLoop(
  1490. FILE *fp,
  1491. BOOL bDisplayPrompt
  1492. )
  1493. {
  1494. LPWSTR pwszFullCommand, p, pwszCmdLine;
  1495. DWORD dwFullCommandLen, dwCmdLineLen, dwErr = NO_ERROR;
  1496. DWORD dwAnyErr = NO_ERROR;
  1497. BOOL bEof, bDone;
  1498. for ( ; ; )
  1499. {
  1500. pwszFullCommand = NULL;
  1501. dwFullCommandLen = 0;
  1502. bEof = FALSE;
  1503. if (bDisplayPrompt)
  1504. {
  1505. if (g_pwszRouterName)
  1506. {
  1507. PrintMessage(L"[%1!s!] ", g_pwszRouterName);
  1508. }
  1509. if (g_pwszContext[0] is L'\0')
  1510. {
  1511. PrintMessage(RtmonPrompt);
  1512. }
  1513. else
  1514. {
  1515. PrintMessage(L"%1!s!>",g_pwszContext);
  1516. }
  1517. }
  1518. // Get an entire command
  1519. for (;;)
  1520. {
  1521. // Get a single line, which may be \ terminated
  1522. pwszCmdLine = OEMfgets(&dwCmdLineLen, fp);
  1523. if (pwszCmdLine is NULL)
  1524. {
  1525. bEof = TRUE;
  1526. break;
  1527. }
  1528. p = pwszCmdLine + (dwCmdLineLen-1);
  1529. // Trim trailing whitespace
  1530. while ((p > pwszCmdLine) && iswspace(p[-1]))
  1531. {
  1532. *(--p) = 0;
  1533. }
  1534. if ((p > pwszCmdLine) && (p[-1] is '\\'))
  1535. {
  1536. // Strip '\\' from the end of the line
  1537. *(--p) = 0;
  1538. // Append line to the full command
  1539. AppendLineToCommand( pwszCmdLine,
  1540. (DWORD)(p-pwszCmdLine),
  1541. &pwszFullCommand,
  1542. &dwFullCommandLen );
  1543. FREE(pwszCmdLine);
  1544. continue; // Get more input
  1545. }
  1546. // Append line to the full command
  1547. AppendLineToCommand( pwszCmdLine,
  1548. (DWORD)(p-pwszCmdLine),
  1549. &pwszFullCommand,
  1550. &dwFullCommandLen );
  1551. // We're done
  1552. FREE(pwszCmdLine);
  1553. break;
  1554. }
  1555. if (bEof)
  1556. {
  1557. break;
  1558. }
  1559. dwErr = ProcessCommand(pwszFullCommand, &bDone);
  1560. if (bDone || g_bDone)
  1561. {
  1562. FREE(pwszFullCommand);
  1563. break;
  1564. }
  1565. if (dwErr)
  1566. {
  1567. dwAnyErr = dwErr;
  1568. }
  1569. FREE(pwszFullCommand);
  1570. }
  1571. return dwAnyErr;
  1572. }
  1573. DWORD
  1574. LoadScriptFile(
  1575. IN LPCWSTR pwszFileName
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. Reads in commands from the file and processes them.
  1580. Arguments:
  1581. pwszFileName - Name of script file.
  1582. Return Value:
  1583. TRUE, FALSE
  1584. --*/
  1585. {
  1586. FILE* fp;
  1587. DWORD i, dwErr = NO_ERROR;
  1588. BOOL bOldInteractive = g_bInteractive;
  1589. BOOL bOldQuiet = g_bQuiet;
  1590. if ((fp = _wfopen(pwszFileName,L"r")) is NULL)
  1591. {
  1592. PrintMessageFromModule(g_hModule, MSG_OPEN_FAILED, pwszFileName);
  1593. return GetLastError();
  1594. }
  1595. g_bInteractive = TRUE;
  1596. g_bQuiet = TRUE;
  1597. dwErr = MainCommandLoop(fp, FALSE);
  1598. g_bInteractive = bOldInteractive;
  1599. g_bQuiet = bOldQuiet;
  1600. fclose(fp);
  1601. if (dwErr)
  1602. {
  1603. dwErr = ERROR_SUPPRESS_OUTPUT;
  1604. }
  1605. return dwErr;
  1606. }
  1607. // This drops the IPC$ connection to the remote machine (if any).
  1608. // This function is called when we switch to a new machine, or netsh finally exits.
  1609. //
  1610. // deonb 7 Dec 2001
  1611. DWORD DisconnectFromCurrentRouter()
  1612. {
  1613. DWORD dwErr = NO_ERROR;
  1614. if (g_pwszRememberedConnection)
  1615. {
  1616. dwErr = WNetCancelConnection2(g_pwszRememberedConnection, 0, TRUE);
  1617. if (dwErr)
  1618. {
  1619. PrintError(NULL, dwErr);
  1620. }
  1621. FREE(g_pwszRememberedConnection);
  1622. g_pwszRememberedConnection = NULL;
  1623. }
  1624. return dwErr;
  1625. }
  1626. DWORD
  1627. SetMachine(
  1628. IN LPCWSTR pwszNewRouter,
  1629. IN LPCWSTR pwszUserName,
  1630. IN LPCWSTR pwszPassword
  1631. )
  1632. {
  1633. HRESULT hr;
  1634. if (g_pwszRouterName)
  1635. {
  1636. FREE(g_pwszRouterName);
  1637. }
  1638. DisconnectFromCurrentRouter();
  1639. if (pwszNewRouter)
  1640. {
  1641. g_pwszRouterName = MALLOC((wcslen(pwszNewRouter) + 1) * sizeof(WCHAR));
  1642. if (!g_pwszRouterName)
  1643. {
  1644. return ERROR_NOT_ENOUGH_MEMORY;
  1645. }
  1646. wcscpy(g_pwszRouterName, pwszNewRouter);
  1647. }
  1648. else
  1649. {
  1650. g_pwszRouterName = NULL;
  1651. }
  1652. // Change back to root context
  1653. SetContext(DEFAULT_STARTUP_CONTEXT);
  1654. hr = UpdateVersionInfoGlobals(g_pwszRouterName, pwszUserName, pwszPassword);
  1655. if (FAILED(hr))
  1656. {
  1657. if (g_pwszRouterName)
  1658. {
  1659. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, g_pwszRouterName);
  1660. }
  1661. else
  1662. {
  1663. TCHAR szComputerName[MAX_PATH];
  1664. DWORD dwComputerNameLen = MAX_PATH;
  1665. GetComputerName(szComputerName, &dwComputerNameLen);
  1666. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, szComputerName);
  1667. }
  1668. PrintError(NULL, hr);
  1669. }
  1670. // Also create a connection to that machine on IPC$. This eliminates the need
  1671. // to do a net use before netsh, and then specify the username & password AGAIN to the
  1672. // netsh command line.
  1673. if (g_pwszRouterName && (pwszUserName || pwszPassword) )
  1674. {
  1675. WCHAR szIPC[MAX_PATH];
  1676. NETRESOURCE NetResource;
  1677. wsprintf(szIPC, L"\\\\%s\\ipc$", g_pwszRouterName);
  1678. ZeroMemory(&NetResource, sizeof(NETRESOURCE));
  1679. NetResource.dwType = RESOURCETYPE_ANY;
  1680. NetResource.lpLocalName = NULL;
  1681. NetResource.lpProvider = NULL;
  1682. NetResource.lpRemoteName= szIPC; // OS Selects a provider
  1683. hr = WNetAddConnection2(&NetResource, pwszPassword, pwszUserName, CONNECT_COMMANDLINE | CONNECT_INTERACTIVE);
  1684. if (S_OK == hr)
  1685. {
  1686. g_pwszRememberedConnection = MALLOC(sizeof(WCHAR) * MAX_PATH);
  1687. if (!g_pwszRememberedConnection)
  1688. {
  1689. PrintMessageFromModule(NULL, ERROR_OUTOFMEMORY);
  1690. return NO_ERROR; // don't fail the set machine since it did actually work if we're at this point.
  1691. }
  1692. wcsncpy(g_pwszRememberedConnection, szIPC, MAX_PATH);
  1693. }
  1694. else
  1695. {
  1696. PrintError(NULL, hr);
  1697. }
  1698. }
  1699. return NO_ERROR;
  1700. }
  1701. void SetThreadCodePage()
  1702. {
  1703. LANGID (WINAPI *pSetThreadUILanguage)() = NULL;
  1704. HMODULE hKernel32 = NULL;
  1705. hKernel32 = LoadLibrary(L"kernel32.dll");
  1706. if (hKernel32)
  1707. {
  1708. pSetThreadUILanguage = (PVOID) GetProcAddress( hKernel32, "SetThreadUILanguage" );
  1709. // OS Platforms before WinXP doesn't support MUI command line utilities so
  1710. // we don't need to worry about it if the O/S doesn't support this API.
  1711. if (pSetThreadUILanguage)
  1712. {
  1713. (*pSetThreadUILanguage)( 0 );
  1714. }
  1715. FreeLibrary(hKernel32);
  1716. }
  1717. }
  1718. int
  1719. MainFunction(
  1720. int argc,
  1721. WCHAR *argv[]
  1722. )
  1723. {
  1724. WCHAR pwszCmdLine[MAX_CMD_LEN] = L"\0";
  1725. WCHAR pwszArgContext[MAX_CMD_LEN] = L"\0";
  1726. BOOL bOnce = FALSE, bDone = FALSE;
  1727. LPCWSTR pwszArgAlias = NULL;
  1728. LPCWSTR pwszArgScript = NULL;
  1729. DWORD dwErr = NO_ERROR, i;
  1730. LPCWSTR p;
  1731. HRESULT hr;
  1732. LPCWSTR pwszMachineName = NULL;
  1733. LPCWSTR pwszUserName = NULL;
  1734. LPCWSTR pwszPassword = NULL;
  1735. WCHAR szPasswordPrompt[MAX_PATH];
  1736. if ((g_hModule = GetModuleHandle(NULL)) is NULL)
  1737. {
  1738. PRINT1("GetModuleHandle failed");
  1739. return 1;
  1740. }
  1741. swprintf(RtmonPrompt, L"%s>", STRING_NETSH);
  1742. //
  1743. // Initialize the Alias Table
  1744. //
  1745. dwErr = ATInitTable();
  1746. if (dwErr isnot NO_ERROR)
  1747. {
  1748. return 0;
  1749. }
  1750. // Initialize the root helper
  1751. AddDllEntry(L"", L"netsh.exe");
  1752. //
  1753. // Load information about the helpers from the registry.
  1754. //
  1755. LoadDllInfoFromRegistry();
  1756. // Need to set the Ctrl Handler so it can catch the Ctrl C and close window events.
  1757. // This is done so the helper dlls can properly be unloaded.
  1758. //
  1759. SetConsoleCtrlHandler(HandlerRoutine,
  1760. TRUE);
  1761. //
  1762. // Set TEB's language ID to correspond to the console output code page. This
  1763. // will ensure the correct language message is displayed when FormatMessage is
  1764. // called.
  1765. //
  1766. SetThreadCodePage();
  1767. for ( i = 1; i < (DWORD) argc; i++ )
  1768. {
  1769. if (_wcsicmp(argv[i], L"-?")==0 ||
  1770. _wcsicmp(argv[i], L"-h")==0 ||
  1771. _wcsicmp(argv[i], L"?" )==0 ||
  1772. _wcsicmp(argv[i], L"/?")==0)
  1773. {
  1774. (VOID) UpdateVersionInfoGlobals(NULL, NULL, NULL);
  1775. // deonb: If this fails we want to restrict the helper from showing up in the context - ignoring
  1776. // the return value will accomplish this.
  1777. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1778. ProcessCommand(L"?", &bDone);
  1779. // Need to free the helper DLLs before we exit
  1780. //
  1781. FreeHelpers();
  1782. FreeDlls();
  1783. return 1;
  1784. }
  1785. if (_wcsicmp(argv[i], L"-v") == 0)
  1786. {
  1787. g_bVerbose = TRUE;
  1788. continue;
  1789. }
  1790. if (_wcsicmp(argv[i], L"-a") == 0)
  1791. {
  1792. //
  1793. // alias file
  1794. //
  1795. if (i + 1 >= (DWORD)argc)
  1796. {
  1797. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1798. dwErr = ERROR_INVALID_SYNTAX;
  1799. break;
  1800. }
  1801. else
  1802. {
  1803. pwszArgAlias = argv[i+1];
  1804. i++;
  1805. continue;
  1806. }
  1807. }
  1808. if (_wcsicmp(argv[i], L"-c") == 0)
  1809. {
  1810. //
  1811. // starting context
  1812. //
  1813. if (i + 1 >= (DWORD)argc)
  1814. {
  1815. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1816. dwErr = ERROR_INVALID_SYNTAX;
  1817. break;
  1818. }
  1819. else
  1820. {
  1821. wcscpy(pwszArgContext, argv[i+1]);
  1822. i++;
  1823. continue;
  1824. }
  1825. }
  1826. if (_wcsicmp(argv[i], L"-f") == 0)
  1827. {
  1828. //
  1829. // command to run
  1830. //
  1831. if (i + 1 >= (DWORD)argc)
  1832. {
  1833. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1834. dwErr = ERROR_INVALID_SYNTAX;
  1835. break;
  1836. }
  1837. else
  1838. {
  1839. pwszArgScript = argv[i+1];
  1840. i++;
  1841. bOnce = TRUE;
  1842. continue;
  1843. }
  1844. }
  1845. #ifdef ALLOW_REMOTES
  1846. if (_wcsicmp(argv[i], L"-r") == 0)
  1847. {
  1848. //
  1849. // router name
  1850. //
  1851. if (i + 1 >= (DWORD)argc)
  1852. {
  1853. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1854. dwErr = ERROR_INVALID_SYNTAX;
  1855. break;
  1856. }
  1857. else
  1858. {
  1859. if (wcslen(argv[i+1]))
  1860. {
  1861. pwszMachineName = argv[i+1];
  1862. }
  1863. i++;
  1864. continue;
  1865. }
  1866. }
  1867. if (_wcsicmp(argv[i], L"-u") == 0)
  1868. {
  1869. //
  1870. // user name
  1871. //
  1872. if (i + 1 >= (DWORD)argc)
  1873. {
  1874. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1875. dwErr = ERROR_INVALID_SYNTAX;
  1876. break;
  1877. }
  1878. else
  1879. {
  1880. if (wcslen(argv[i+1]))
  1881. {
  1882. pwszUserName = argv[i+1];
  1883. }
  1884. i++;
  1885. continue;
  1886. }
  1887. }
  1888. if (_wcsicmp(argv[i], L"-p") == 0)
  1889. {
  1890. //
  1891. // password
  1892. //
  1893. if (i + 1 >= (DWORD)argc)
  1894. {
  1895. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1896. dwErr = ERROR_INVALID_SYNTAX;
  1897. break;
  1898. }
  1899. else
  1900. {
  1901. if (wcslen(argv[i+1]))
  1902. {
  1903. pwszPassword = argv[i+1];
  1904. }
  1905. i++;
  1906. continue;
  1907. }
  1908. }
  1909. #endif
  1910. if (!bOnce)
  1911. {
  1912. while (i < (DWORD)argc)
  1913. {
  1914. if (pwszCmdLine[0])
  1915. {
  1916. wcscat(pwszCmdLine, L" ");
  1917. }
  1918. p = argv[i];
  1919. if (!p[0] || wcschr(argv[i], L' '))
  1920. {
  1921. wcscat(pwszCmdLine, L"\"");
  1922. wcscat(pwszCmdLine, p);
  1923. wcscat(pwszCmdLine, L"\"");
  1924. }
  1925. else
  1926. {
  1927. wcscat(pwszCmdLine, p);
  1928. }
  1929. i++;
  1930. }
  1931. }
  1932. else
  1933. {
  1934. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1935. dwErr = ERROR_INVALID_SYNTAX;
  1936. }
  1937. break;
  1938. }
  1939. do
  1940. {
  1941. if (dwErr isnot NO_ERROR)
  1942. {
  1943. break;
  1944. }
  1945. if (pwszMachineName)
  1946. {
  1947. if (pwszPassword && _wcsicmp(pwszPassword, L"*") == 0)
  1948. {
  1949. DWORD dwLen = 0;
  1950. PrintMessageFromModule(g_hModule, MSG_NETSH_LOGIN_PASSWORD, pwszMachineName);
  1951. if (0 != GetPasswdStr(szPasswordPrompt, MAX_PATH, &dwLen))
  1952. {
  1953. dwErr = ERROR_INVALID_SYNTAX;
  1954. break;
  1955. }
  1956. else
  1957. {
  1958. pwszPassword = szPasswordPrompt;
  1959. }
  1960. }
  1961. dwErr = SetMachine( pwszMachineName, pwszUserName, pwszPassword );
  1962. if (dwErr isnot NO_ERROR)
  1963. {
  1964. PrintMessageFromModule(g_hModule, dwErr);
  1965. break;
  1966. }
  1967. }
  1968. if (!g_pwszRouterName)
  1969. {
  1970. hr = UpdateVersionInfoGlobals(NULL, NULL, NULL); // Update the info for the local machine
  1971. if (FAILED(hr))
  1972. {
  1973. if (g_pwszRouterName)
  1974. {
  1975. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, g_pwszRouterName);
  1976. }
  1977. else
  1978. {
  1979. TCHAR szComputerName[MAX_PATH];
  1980. DWORD dwComputerNameLen = MAX_PATH;
  1981. GetComputerName(szComputerName, &dwComputerNameLen);
  1982. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, szComputerName);
  1983. }
  1984. PrintError(NULL, hr);
  1985. }
  1986. }
  1987. if (pwszArgAlias)
  1988. {
  1989. dwErr = LoadScriptFile(pwszArgAlias);
  1990. if (dwErr)
  1991. {
  1992. break;
  1993. }
  1994. }
  1995. if (pwszArgContext[0] != L'\0')
  1996. {
  1997. // The context switch command should be processed in
  1998. // interactive mode (which is the only time a context
  1999. // switch is legal).
  2000. g_bInteractive = TRUE;
  2001. dwErr = ProcessCommand(pwszArgContext, &bDone);
  2002. g_bInteractive = FALSE;
  2003. if (dwErr)
  2004. {
  2005. break;
  2006. }
  2007. }
  2008. if (pwszCmdLine[0] != L'\0')
  2009. {
  2010. g_bQuiet = FALSE; // Bug# 262183
  2011. dwErr = ProcessCommand(pwszCmdLine, &bDone);
  2012. break;
  2013. }
  2014. if (pwszArgScript)
  2015. {
  2016. g_bInteractive = TRUE;
  2017. dwErr = LoadScriptFile(pwszArgScript);
  2018. break;
  2019. }
  2020. g_bInteractive = TRUE;
  2021. g_bQuiet = FALSE;
  2022. // Main command loop
  2023. dwErr = MainCommandLoop(stdin, TRUE);
  2024. } while (FALSE);
  2025. //
  2026. // Clean up
  2027. //
  2028. DisconnectFromCurrentRouter();
  2029. FreeHelpers();
  2030. FreeDlls();
  2031. FreeAliasTable();
  2032. if(g_pwszRouterName)
  2033. {
  2034. FREE(g_pwszRouterName);
  2035. g_pwszRouterName = NULL;
  2036. }
  2037. // Return 1 on error, 0 if not
  2038. return (dwErr isnot NO_ERROR);
  2039. }
  2040. int _cdecl
  2041. wmain(
  2042. int argc,
  2043. WCHAR *argv[]
  2044. )
  2045. /*++
  2046. Routine Description:
  2047. The main function.
  2048. Arguments:
  2049. Return Value:
  2050. --*/
  2051. {
  2052. HANDLE hStdOut;
  2053. DWORD dwRet;
  2054. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2055. WORD oldXSize;
  2056. char buff[256];
  2057. WSADATA wsaData;
  2058. HRESULT hr;
  2059. #if 0
  2060. hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  2061. if (hStdOut is INVALID_HANDLE_VALUE)
  2062. {
  2063. PRINT1("Standard output could not be opened.");
  2064. return 0;
  2065. }
  2066. GetConsoleScreenBufferInfo(hStdOut, &csbi);
  2067. oldXSize = csbi.dwSize.X;
  2068. csbi.dwSize.X = 120;
  2069. SetConsoleScreenBufferSize(hStdOut, csbi.dwSize);
  2070. #endif
  2071. #if 0
  2072. WSAStartup(MAKEWORD(2,0), &wsaData);
  2073. if (!gethostname(buff, sizeof(buff)))
  2074. {
  2075. g_pwszRouterName = MALLOC( (strlen(buff)+1) * sizeof(WCHAR) );
  2076. swprintf(g_pwszRouterName, L"%hs", buff);
  2077. }
  2078. #endif
  2079. dwRet = MainFunction(argc, argv);
  2080. #if 0
  2081. GetConsoleScreenBufferInfo(hStdOut, &csbi);
  2082. csbi.dwSize.X = oldXSize;
  2083. SetConsoleScreenBufferSize(hStdOut, csbi.dwSize);
  2084. CloseHandle(hStdOut);
  2085. #endif
  2086. return dwRet;
  2087. }
  2088. BOOL
  2089. IsLocalCommand(
  2090. IN LPCWSTR pwszCmd,
  2091. IN DWORD dwSkipFlags
  2092. )
  2093. /*++
  2094. Arguments:
  2095. pwszCmd - string to see if it matches a command
  2096. dwSkipFlags - any commands with these flags will be ignored.
  2097. This is the opposite semantics of the "dwDisplayFlags"
  2098. parameter used elsewhere (dwSkipFlags = ~dwDisplayFlags)
  2099. --*/
  2100. {
  2101. DWORD i, dwErr;
  2102. PCNS_CONTEXT_ATTRIBUTES pContext, pSubContext;
  2103. PNS_HELPER_TABLE_ENTRY pHelper;
  2104. dwErr = GetRootContext( &pContext, &pHelper );
  2105. if (dwErr)
  2106. {
  2107. return FALSE;
  2108. }
  2109. for (i=0; i<g_ulNumShellCmds; i++)
  2110. {
  2111. if (!(g_ShellCmds[i].dwFlags & dwSkipFlags)
  2112. && !_wcsicmp( pwszCmd,
  2113. g_ShellCmds[i].pwszCmdToken ))
  2114. {
  2115. return TRUE;
  2116. }
  2117. }
  2118. for (i=0; i<g_ulNumGroups; i++)
  2119. {
  2120. if (!(g_ShellCmdGroups[i].dwFlags & dwSkipFlags)
  2121. && !_wcsicmp( pwszCmd,
  2122. g_ShellCmdGroups[i].pwszCmdGroupToken ))
  2123. {
  2124. return TRUE;
  2125. }
  2126. }
  2127. for (i=0; i<pHelper->ulNumSubContexts; i++)
  2128. {
  2129. pSubContext = (PCNS_CONTEXT_ATTRIBUTES)
  2130. (pHelper->pSubContextTable + i*pHelper->ulSubContextSize);
  2131. if (!(pSubContext->dwFlags & dwSkipFlags)
  2132. && !_wcsicmp( pwszCmd,
  2133. pSubContext->pwszContext))
  2134. {
  2135. return TRUE;
  2136. }
  2137. }
  2138. return FALSE;
  2139. }