Source code of Windows XP (NT5)
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.

385 lines
10 KiB

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