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.

388 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. ParseDde.cpp
  5. Abstract:
  6. Useful routines for parsing DDE commands.
  7. History:
  8. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  9. 03/12/2002 robkenny Security review.
  10. --*/
  11. //
  12. // This code was copied from:
  13. // \\index1\src\shell\shell32\unicpp\dde.cpp
  14. // with minimal processing.
  15. //
  16. #include "Windows.h"
  17. #include "StrSafe.h"
  18. #include "ParseDDE.h"
  19. #include <ShlObj.h>
  20. namespace ShimLib
  21. {
  22. //--------------------------------------------------------------------------
  23. // Returns a pointer to the first non-whitespace character in a string.
  24. LPSTR SkipWhite(LPSTR lpsz)
  25. {
  26. /* prevent sign extension in case of DBCS */
  27. while (*lpsz && (UCHAR)*lpsz <= ' ')
  28. lpsz++;
  29. return(lpsz);
  30. }
  31. LPSTR GetCommandName(LPSTR lpCmd, const char * lpsCommands[], UINT *lpW)
  32. {
  33. CHAR chT;
  34. UINT iCmd = 0;
  35. LPSTR lpT;
  36. /* Eat any white space. */
  37. lpCmd = SkipWhite(lpCmd);
  38. lpT = lpCmd;
  39. /* Find the end of the token. */
  40. while (IsCharAlpha(*lpCmd))
  41. lpCmd = CharNextA(lpCmd);
  42. /* Temporarily NULL terminate it. */
  43. chT = *lpCmd;
  44. *lpCmd = 0;
  45. /* Look up the token in a list of commands. */
  46. *lpW = (UINT)-1;
  47. while (*lpsCommands)
  48. {
  49. const char * knownCommand = *lpsCommands;
  50. if (!_strcmpi(knownCommand, lpT))
  51. {
  52. *lpW = iCmd;
  53. break;
  54. }
  55. iCmd++;
  56. ++lpsCommands;
  57. }
  58. *lpCmd = chT;
  59. return(lpCmd);
  60. }
  61. //--------------------------------------------------------------------------
  62. // Reads a parameter out of a string removing leading and trailing whitespace.
  63. // Terminated by , or ). ] [ and ( are not allowed. Exception: quoted
  64. // strings are treated as a whole parameter and may contain []() and ,.
  65. // Places the offset of the first character of the parameter into some place
  66. // and NULL terminates the parameter.
  67. // If fIncludeQuotes is false it is assumed that quoted strings will contain single
  68. // commands (the quotes will be removed and anything following the quotes will
  69. // be ignored until the next comma). If fIncludeQuotes is TRUE, the contents of
  70. // the quoted string will be ignored as before but the quotes won't be
  71. // removed and anything following the quotes will remain.
  72. LPSTR GetOneParameter(LPCSTR lpCmdStart, LPSTR lpCmd,
  73. UINT *lpW, BOOL fIncludeQuotes)
  74. {
  75. LPSTR lpT;
  76. switch (*lpCmd)
  77. {
  78. case ',':
  79. *lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
  80. *lpCmd++ = 0; /* comma: becomes a NULL string */
  81. break;
  82. case '"':
  83. if (fIncludeQuotes)
  84. {
  85. //TraceMsg(TF_DDE, "GetOneParameter: Keeping quotes.");
  86. // quoted string... don't trim off "
  87. *lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
  88. ++lpCmd;
  89. while (*lpCmd && *lpCmd != '"')
  90. lpCmd = CharNextA(lpCmd);
  91. if (!*lpCmd)
  92. return(NULL);
  93. lpT = lpCmd;
  94. ++lpCmd;
  95. goto skiptocomma;
  96. }
  97. else
  98. {
  99. // quoted string... trim off "
  100. ++lpCmd;
  101. *lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
  102. while (*lpCmd && *lpCmd != '"')
  103. lpCmd = CharNextA(lpCmd);
  104. if (!*lpCmd)
  105. return(NULL);
  106. *lpCmd++ = 0;
  107. lpCmd = SkipWhite(lpCmd);
  108. // If there's a comma next then skip over it, else just go on as
  109. // normal.
  110. if (*lpCmd == ',')
  111. lpCmd++;
  112. }
  113. break;
  114. case ')':
  115. return(lpCmd); /* we ought not to hit this */
  116. case '(':
  117. case '[':
  118. case ']':
  119. return(NULL); /* these are illegal */
  120. default:
  121. lpT = lpCmd;
  122. *lpW = (UINT) (lpCmd - lpCmdStart); // compute offset
  123. skiptocomma:
  124. while (*lpCmd && *lpCmd != ',' && *lpCmd != ')')
  125. {
  126. /* Check for illegal characters. */
  127. if (*lpCmd == ']' || *lpCmd == '[' || *lpCmd == '(' )
  128. return(NULL);
  129. /* Remove trailing whitespace */
  130. /* prevent sign extension */
  131. if (*lpCmd > ' ')
  132. lpT = lpCmd;
  133. lpCmd = CharNextA(lpCmd);
  134. }
  135. /* Eat any trailing comma. */
  136. if (*lpCmd == ',')
  137. lpCmd++;
  138. /* NULL terminator after last nonblank character -- may write over
  139. * terminating ')' but the caller checks for that because this is
  140. * a hack.
  141. */
  142. #ifdef UNICODE
  143. lpT[1] = 0;
  144. #else
  145. lpT[IsDBCSLeadByte(*lpT) ? 2 : 1] = 0;
  146. #endif
  147. break;
  148. }
  149. // Return next unused character.
  150. return(lpCmd);
  151. }
  152. // Extracts an alphabetic string and looks it up in a list of possible
  153. // commands, returning a pointer to the character after the command and
  154. // sticking the command index somewhere.
  155. UINT* GetDDECommands(LPSTR lpCmd, const char * lpsCommands[], BOOL fLFN)
  156. {
  157. UINT cParm, cCmd = 0;
  158. UINT *lpW;
  159. UINT *lpRet;
  160. LPCSTR lpCmdStart = lpCmd;
  161. BOOL fIncludeQuotes = FALSE;
  162. if (lpCmd == NULL)
  163. return NULL;
  164. lpRet = lpW = (UINT*)GlobalAlloc(GPTR, 512L);
  165. if (!lpRet)
  166. return 0;
  167. while (*lpCmd)
  168. {
  169. /* Skip leading whitespace. */
  170. lpCmd = SkipWhite(lpCmd);
  171. /* Are we at a NULL? */
  172. if (!*lpCmd)
  173. {
  174. /* Did we find any commands yet? */
  175. if (cCmd)
  176. goto GDEExit;
  177. else
  178. goto GDEErrExit;
  179. }
  180. /* Each command should be inside square brackets. */
  181. if (*lpCmd != '[')
  182. goto GDEErrExit;
  183. lpCmd++;
  184. /* Get the command name. */
  185. lpCmd = GetCommandName(lpCmd, lpsCommands, lpW);
  186. if (*lpW == (UINT)-1)
  187. goto GDEErrExit;
  188. // We need to leave quotes in for the first param of an AddItem.
  189. if (fLFN && *lpW == 2)
  190. {
  191. //TraceMsg(TF_DDE, "GetDDECommands: Potential LFN AddItem command...");
  192. fIncludeQuotes = TRUE;
  193. }
  194. lpW++;
  195. /* Start with zero parms. */
  196. cParm = 0;
  197. lpCmd = SkipWhite(lpCmd);
  198. /* Check for opening '(' */
  199. if (*lpCmd == '(')
  200. {
  201. lpCmd++;
  202. /* Skip white space and then find some parameters (may be none). */
  203. lpCmd = SkipWhite(lpCmd);
  204. while (*lpCmd != ')')
  205. {
  206. if (!*lpCmd)
  207. goto GDEErrExit;
  208. // Only the first param of the AddItem command needs to
  209. // handle quotes from LFN guys.
  210. if (fIncludeQuotes && (cParm != 0))
  211. fIncludeQuotes = FALSE;
  212. /* Get the parameter. */
  213. lpCmd = GetOneParameter(lpCmdStart, lpCmd, lpW + (++cParm), fIncludeQuotes);
  214. if (!lpCmd)
  215. goto GDEErrExit;
  216. /* HACK: Did GOP replace a ')' with a NULL? */
  217. if (!*lpCmd)
  218. break;
  219. /* Find the next one or ')' */
  220. lpCmd = SkipWhite(lpCmd);
  221. }
  222. // Skip closing bracket.
  223. lpCmd++;
  224. /* Skip the terminating stuff. */
  225. lpCmd = SkipWhite(lpCmd);
  226. }
  227. /* Set the count of parameters and then skip the parameters. */
  228. *lpW++ = cParm;
  229. lpW += cParm;
  230. /* We found one more command. */
  231. cCmd++;
  232. /* Commands must be in square brackets. */
  233. if (*lpCmd != ']')
  234. goto GDEErrExit;
  235. lpCmd++;
  236. }
  237. GDEExit:
  238. /* Terminate the command list with -1. */
  239. *lpW = (UINT)-1;
  240. return lpRet;
  241. GDEErrExit:
  242. GlobalFree(lpW);
  243. return(0);
  244. }
  245. BOOL SHTestTokenMembership (HANDLE hToken, ULONG ulRID)
  246. {
  247. static SID_IDENTIFIER_AUTHORITY sSystemSidAuthority = SECURITY_NT_AUTHORITY;
  248. BOOL fResult;
  249. PSID pSIDLocalGroup;
  250. fResult = FALSE;
  251. if (AllocateAndInitializeSid(&sSystemSidAuthority,
  252. 2,
  253. SECURITY_BUILTIN_DOMAIN_RID,
  254. ulRID,
  255. 0, 0, 0, 0, 0, 0,
  256. &pSIDLocalGroup) != FALSE)
  257. {
  258. if (CheckTokenMembership(hToken, pSIDLocalGroup, &fResult) == FALSE)
  259. {
  260. //TraceMsg(TF_WARNING, "shell32: SHTestTokenMembership call to advapi32!CheckTokenMembership failed with error %d", GetLastError());
  261. fResult = FALSE;
  262. }
  263. (void*)FreeSid(pSIDLocalGroup);
  264. }
  265. return(fResult);
  266. }
  267. BOOL IsUserAnAdmin()
  268. {
  269. return(SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS));
  270. }
  271. // Map the group name to a proper path taking care of the startup group and
  272. // app hacks on the way.
  273. void GetGroupPath(LPCSTR pszName, CString & csPath, DWORD /*dwFlags*/, INT iCommonGroup)
  274. {
  275. BOOL bCommonGroup;
  276. if (IsUserAnAdmin()) {
  277. if (iCommonGroup == 0) {
  278. bCommonGroup = FALSE;
  279. } else if (iCommonGroup == 1) {
  280. bCommonGroup = TRUE;
  281. } else {
  282. //
  283. // Administrators get common groups created by default
  284. // when the setup application doesn't specificly state
  285. // what kind of group to create. This feature can be
  286. // turned off in the cabinet state flags.
  287. //
  288. //CABINETSTATE cs;
  289. //ReadCabinetState(&cs, sizeof(cs));
  290. //if (cs.fAdminsCreateCommonGroups) {
  291. // bFindPersonalGroup = TRUE;
  292. // bCommonGroup = FALSE; // This might get turned on later
  293. // // if find is unsuccessful
  294. //} else {
  295. // bCommonGroup = FALSE;
  296. //}
  297. bCommonGroup = TRUE;
  298. }
  299. } else {
  300. //
  301. // Regular users can't create common group items.
  302. //
  303. bCommonGroup = FALSE;
  304. }
  305. // Build a path to the directory
  306. if (bCommonGroup) {
  307. SHGetSpecialFolderPathW(csPath, CSIDL_COMMON_PROGRAMS, NULL);
  308. } else {
  309. SHGetSpecialFolderPathW(csPath, CSIDL_PROGRAMS, NULL);
  310. }
  311. CString csName(pszName);
  312. csPath.AppendPath(csName);
  313. }
  314. }; // end of namespace ShimLib