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.

459 lines
11 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2001.
  5. //
  6. // File: cmdkey: command.cpp
  7. //
  8. // Contents: Command line parsing functions
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 07-09-01 georgema Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "command.h"
  22. #include "switches.h"
  23. #ifdef CLPARSER
  24. WCHAR szsz[500];
  25. #define ODS(x) OutputDebugString(x)
  26. #endif
  27. static BOOL *pf = NULL;
  28. static INT iMaxCommand = -1;
  29. static INT iFirstCommand = -1;
  30. static WCHAR *pModel = NULL;
  31. static WCHAR **pprgc = NULL;
  32. static WCHAR *pCmdline = NULL;
  33. static INT cSwitches = 0;
  34. static BOOL fExtra = FALSE;
  35. static WCHAR rgcAll[] = {L"abcdefghijklmnopqrstuvwxyz?0123456789"};
  36. #define ccAll (sizeof(rgcAll) / sizeof(WCHAR))
  37. // -------------------------------------------------------------------------
  38. //
  39. // Command Parser exports
  40. //
  41. // -------------------------------------------------------------------------
  42. // Get access to the command switches model and the count of valid switches
  43. // Create variables for use by the parser
  44. BOOL CLInit(void)
  45. {
  46. return CLInit((INT) ccAll,rgcAll);
  47. }
  48. BOOL CLInit(INT ccSwitches, WCHAR *prgc)
  49. {
  50. if (NULL == prgc) return FALSE;
  51. if (0 >= ccSwitches) return FALSE;
  52. // note that GetCommandLine() does not return any cr/lf at the end of the string, just NULL.
  53. pCmdline = GetCommandLineW();
  54. #ifdef CLPARSER
  55. swprintf(szsz,L"CMDKEY: Command line :%s\n",pCmdline);
  56. ODS(szsz);
  57. #endif
  58. pModel = prgc;
  59. cSwitches = ccSwitches;
  60. // accept a count of switches, generate the appropriate
  61. // intermediate variables for the parser
  62. pprgc = (WCHAR **) malloc(sizeof(WCHAR*) * (cSwitches + 1));
  63. if (NULL == pprgc) return FALSE;
  64. pf = (BOOL *) malloc(sizeof(BOOL) * (cSwitches + 1));
  65. if (NULL == pf) return FALSE;
  66. for (INT i=0;i<cSwitches;i++)
  67. {
  68. pprgc[i] = NULL;
  69. pf[i] = FALSE;
  70. }
  71. return TRUE;
  72. }
  73. // Scan for switches, detecting extraneous ones, and setting the switchpresent flag
  74. // and the switch argument data pointer as appropriate.
  75. //
  76. // Parsing will return failed in the case of finding a duplicate of a switch already
  77. // encountered. In many cases, that can lead to ambiguity. This should be pretty
  78. // uncommon, and will always result from bad input from the user.
  79. BOOL CLParse(void)
  80. {
  81. BOOL fOK = TRUE;
  82. WCHAR *pc = pCmdline;
  83. WCHAR *pa = NULL;
  84. WCHAR c = 0;
  85. INT i = 0;
  86. WCHAR last = 0x0;
  87. #ifdef CLPARSER
  88. WCHAR sz[] = {L" "};
  89. #endif
  90. #ifdef CLPARSER
  91. ODS(L"CMDKEY: Scanning for all switches : ");
  92. #endif
  93. while (0 != (c = *pc++))
  94. {
  95. // char found on command line
  96. if ((c == '/') || (c == '-'))
  97. {
  98. if (last != ' ')
  99. {
  100. // Only valid switchchar if preceded by a space
  101. //last = c;
  102. continue;
  103. }
  104. c = *pc; // fetch next character
  105. if (0 == c) break; // break on end of line
  106. #ifdef CLPARSER
  107. sz[0] = c;
  108. ODS(sz);
  109. #endif
  110. for (i=0; i<cSwitches;i++)
  111. {
  112. c |= 0x20; // force to lower case
  113. if (c == pModel[i]) break; // break the for for char OK
  114. }
  115. if ( i!= cSwitches )
  116. {
  117. if (pf[i])
  118. {
  119. #ifdef CLPARSER
  120. ODS(L"(duplicate!)");
  121. #endif
  122. fOK = FALSE;
  123. break; // fatal parse error - dup switch
  124. }
  125. pf[i] = TRUE;
  126. if (iFirstCommand < 0)
  127. {
  128. if (i <= iMaxCommand)
  129. {
  130. iFirstCommand = i;
  131. #ifdef CLPARSER
  132. ODS(L"!");
  133. #endif
  134. }
  135. }
  136. pa = FetchSwitchString(pc);
  137. if (NULL != pa)
  138. {
  139. pprgc[i] = pa;
  140. #ifdef CLPARSER
  141. swprintf(szsz,L"(%s)",pa);
  142. ODS(szsz);
  143. #endif
  144. }
  145. }
  146. #ifdef PICKY
  147. else
  148. {
  149. // once you find an extraneous switch, cease looking
  150. #ifdef CLPARSER
  151. ODS(L" (*bad*)");
  152. #endif
  153. fExtra = TRUE;
  154. break; // get out of while
  155. }
  156. #endif // PICKY
  157. #ifdef CLPARSER
  158. ODS(L" ");
  159. #endif
  160. }
  161. last = c;
  162. }
  163. #ifdef CLPARSER
  164. ODS(L"\n");
  165. #endif
  166. return fOK;
  167. }
  168. INT
  169. CLSetMaxPrincipalSwitch(INT i)
  170. {
  171. INT iOld = iMaxCommand;
  172. iMaxCommand = i;
  173. return iOld;
  174. }
  175. INT
  176. CLGetPrincipalSwitch(void)
  177. {
  178. return iFirstCommand;
  179. }
  180. // Return TRUE if extraneous switches found
  181. BOOL CLExtra(void)
  182. {
  183. return fExtra;
  184. }
  185. // Return TRUE if the indexed switch was found
  186. BOOL CLFlag(INT i)
  187. {
  188. if (i > cSwitches) return FALSE;
  189. if (i < 0) return FALSE;
  190. return pf[i];
  191. }
  192. // Returns a pointer to a copy of the switch argument data, or NULL if the switch had no data following
  193. WCHAR *CLPtr(INT i)
  194. {
  195. if (i > cSwitches) return NULL;
  196. if (i < 0) return NULL;
  197. return pprgc[i];
  198. }
  199. // Free allocated parser variables
  200. void CLUnInit(void)
  201. {
  202. for (INT i=0;i<cSwitches;i++)
  203. {
  204. if (pprgc[i] != NULL) free((void *) pprgc[i]);
  205. }
  206. if (pprgc) free((void *)pprgc);
  207. if (pf) free((void *)pf);
  208. }
  209. // -------------------------------------------------------------------------
  210. //
  211. // Switch Parsing group
  212. //
  213. // -------------------------------------------------------------------------
  214. // Fetch switch argument after finding switch. Ret ptr to
  215. // first non-whitespace char, place null after last non-whitespace
  216. // char. In the case of quotes, return ptr to 1st char after quote
  217. // and place null over last quote.
  218. //
  219. // Note that whitespace seems to be specifically 0x20. Tabs do not seem to be
  220. // returned from command lines
  221. //
  222. // Place two pointers, one at the beginning, one at the end, work from
  223. // there.
  224. //
  225. // Caller should use the value and then free the string.
  226. WCHAR *FetchSwitchString(WCHAR *origin)
  227. {
  228. WCHAR *p1;
  229. WCHAR *p2;
  230. WCHAR c;
  231. WCHAR l = 0;
  232. BOOL fQ = FALSE;
  233. INT_PTR iLen;
  234. WCHAR *pBuf;
  235. if (NULL == origin) return NULL;
  236. p1 = origin;
  237. // walk to end of switchstring itself
  238. while (1 )
  239. {
  240. c = *p1;
  241. if (c == 0) return NULL; // eol before arg found
  242. // skip to end of switch token
  243. if (c == ':') break; // end of switch
  244. if (c == 0x20) break; // end of switch
  245. if (c == '/') return NULL; // next switch before arg found
  246. if (c == '-') return NULL;
  247. p1++;
  248. l = c;
  249. }
  250. p1++;
  251. // walk to beginning of the switch argument
  252. // eat spaces, step over begin quotes
  253. while (1 )
  254. {
  255. c = *p1;
  256. if (c == '"')
  257. {
  258. fQ = TRUE;
  259. p1++;
  260. l = c;
  261. break;
  262. }
  263. else if (c == 0) return NULL; // did not find an arg
  264. else if (c == '/') return NULL;
  265. else if (c == '-') return NULL;
  266. else if (c > 0x20) break;
  267. p1++;
  268. l = c;
  269. }
  270. // p1 now pointed to root char of switch arg itself
  271. // fQ set if in a quoted string
  272. // Find the end of the arg string
  273. // If a quoted string, only a quote or EOL ends it
  274. // else ended by EOL, switchchar or quote
  275. p2 = p1;
  276. while (1)
  277. {
  278. c = *p2;
  279. if (fQ)
  280. {
  281. if (c == 0) break;
  282. if (c == '"') break;
  283. }
  284. else
  285. {
  286. if (c == 0) break;
  287. // Encountering the next switch terminates the string only if the
  288. // switch char is preceded by a space (valid switchchar)
  289. if (l == ' ')
  290. {
  291. if (c == '/') break;
  292. if (c == '-') break;
  293. }
  294. // disallow embedded quotes
  295. if (c == '"') return NULL;
  296. }
  297. p2++;
  298. l = c;
  299. }
  300. p2--; // ptr to last valid char in arg string
  301. // now back up until you hit the first printable character, IFF the tail ptr is not already
  302. // coincident with the head ptr. In that case, the string length is 1
  303. while (p2 > p1)
  304. {
  305. c = *p2;
  306. if (c > 0x20) break;
  307. p2--;
  308. }
  309. iLen = p2 - p1;
  310. pBuf = (WCHAR *) malloc(iLen * sizeof(WCHAR) + 2 * sizeof(WCHAR));
  311. if (pBuf)
  312. {
  313. memset(pBuf,0,iLen * sizeof(WCHAR) + 2 * sizeof(WCHAR));
  314. wcsncpy(pBuf,p1,iLen + 1);
  315. }
  316. return pBuf;
  317. }
  318. // Return a count of tokens on the command line. The executable name by itself makes 1, so the
  319. // return value is never zero.
  320. int
  321. CLTokens(void)
  322. {
  323. BOOL fQ = FALSE;
  324. WCHAR *p1 = pCmdline;
  325. int i = 0;
  326. WCHAR c;
  327. // walk to beginning of the switch argument
  328. while (1)
  329. {
  330. while (1 )
  331. {
  332. c = *p1;
  333. // handle in and out of quote mode
  334. if (fQ)
  335. if (c == '"')
  336. {
  337. fQ = FALSE; // empty quotation
  338. p1++;
  339. break;
  340. }
  341. if (c == '"')
  342. {
  343. fQ = TRUE;
  344. }
  345. // exit at end of string only
  346. else if (c == 0) return ++i; // did not find an arg
  347. // space between tokens
  348. else if (c <= 0x20)
  349. if (!fQ) break;
  350. // normal character - just keep walking
  351. p1++;
  352. }
  353. ++i;
  354. // skip over whitespace
  355. while (1)
  356. {
  357. c = *p1;
  358. if (c > 0x20) break;
  359. if (c == 0) return i;
  360. p1++;
  361. }
  362. }
  363. }
  364. WCHAR
  365. *CLFirstString(WCHAR *pc)
  366. {
  367. WCHAR *pd = pc;
  368. if (NULL == pc) return NULL;
  369. if (*(pc) == 0) return NULL;
  370. while (*(++pc) > 0x20) continue;
  371. *pc = 0;
  372. return pd;
  373. }
  374. WCHAR
  375. *CLLastString(WCHAR *pc)
  376. {
  377. WCHAR c;
  378. WCHAR *pd = pc;
  379. if (NULL == pc) return NULL;
  380. if (NULL == *pc) return NULL;
  381. while (*(++pc) != 0) continue;
  382. while (pc > pd)
  383. {
  384. c = *(--pc);
  385. if (0 == c) return NULL;
  386. if (0x20 >= c) break;
  387. }
  388. if (pc == pd) return NULL;
  389. return ++pc;
  390. }
  391. // -------------------------------------------------------------------------
  392. //
  393. // Security and Utility Group
  394. //
  395. // -------------------------------------------------------------------------
  396. void StompCommandLine(INT argc, char **argv)
  397. {
  398. //return;
  399. INT cc;
  400. WCHAR *pL = GetCommandLineW();
  401. if (pL)
  402. {
  403. cc = wcslen(pL);
  404. if (cc)
  405. {
  406. SecureZeroMemory(pL,cc * sizeof(WCHAR));
  407. }
  408. }
  409. // remove c runtime copy contents, as well
  410. for (INT i=0 ; i < argc ; i++)
  411. {
  412. cc = strlen( argv[i]);
  413. if (cc)
  414. {
  415. SecureZeroMemory(pL,cc * sizeof(char));
  416. }
  417. }
  418. }