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.

284 lines
7.4 KiB

  1. //---[ wildmat.cpp ]-------------------------------------------------------------
  2. //
  3. // Description:
  4. // Provides support for a simple wildcard matching mechanism for
  5. // matching email addresses.
  6. //
  7. // Copyright (C) Microsoft Corp. 1997. All Rights Reserved.
  8. //
  9. // ---------------------------------------------------------------------------
  10. //
  11. // This stuff is isolated out to simplify unit-testing ...
  12. //
  13. #include "windows.h"
  14. #include "abtype.h"
  15. #include "dbgtrace.h"
  16. static void pStringLower(LPSTR szString, LPSTR szLowerString)
  17. {
  18. while (*szString)
  19. *szLowerString++ = (CHAR)tolower(*szString++);
  20. *szLowerString = '\0';
  21. }
  22. // This stuff is from address.hxx
  23. #define MAX_EMAIL_NAME 64
  24. #define MAX_DOMAIN_NAME 250
  25. #define MAX_INTERNET_NAME (MAX_EMAIL_NAME + MAX_DOMAIN_NAME + 2) // 2 for @ and \0
  26. //
  27. // This is a quick and dirty function to do wildcard matching for email
  28. // names. The match is case-insensitive, and the pattern can be expressed as:
  29. //
  30. // <email pattern>[@<domain pattern>]
  31. //
  32. // The email pattern is expressed as follows:
  33. //
  34. // <email pattern> := { * | [*]<email name>[*] }
  35. //
  36. // Which becomes one of the below:
  37. // * - Any email name
  38. // foo - Exact match for "foo"
  39. // *foo - Any email name ending with "foo", including "foo"
  40. // foo* - Any email name beginning with "foo", including "foo"
  41. // *foo* - Any email name that contains the string "foo", including "foo"
  42. //
  43. // If a domain is not specified, the pattern matches against any domain. Both the
  44. // email pattern and the domain pattern (if specified) must be matched for the
  45. // rule to fire. Domain patterns are expressed as:
  46. //
  47. // <domain pattern> := [*][<domain name>]
  48. //
  49. // Which are:
  50. // * - Any domain
  51. // bar.com - Exact match for "bar.com"
  52. // *bar.com - Any domain ending with "bar.com", including "bar.com"
  53. //
  54. // szEmail must be a string to the email alias (clean without comments, etc.)
  55. // szEmailDomain must be a string to the email domain. NULL means no domain
  56. // is specified. The domain must be clean without comments, etc.
  57. //
  58. //
  59. typedef enum _WILDMAT_MODES
  60. {
  61. WMOD_INVALID = 0,
  62. WMOD_WILDCARD_LEFT, // Wildcard on the left
  63. WMOD_WILDCARD_RIGHT, // Wildcard on the right
  64. WMOD_WILDCARD_BOTH, // Wildcard on both sides
  65. WMOD_WILDCARD_MAX
  66. } WILDMAT_MODES;
  67. HRESULT MatchEmailOrDomainName(LPSTR szEmail, LPSTR szEmailDomain, LPSTR szPattern, BOOL fIsEmail)
  68. {
  69. LPSTR pszPatternDomain;
  70. BOOL fEmailWildMat = FALSE;
  71. BOOL fDomainWildMat = FALSE;
  72. DWORD wmEmailWildMatMode = WMOD_INVALID;
  73. DWORD dwEmailLen = 0, dwDomainLen = 0;
  74. DWORD dwEmailStemLen = 0, dwDomainStemLen = 0;
  75. DWORD i;
  76. HRESULT hrRes = S_OK;
  77. CHAR szDomainMat[MAX_INTERNET_NAME + 1];
  78. TraceFunctEnterEx((LPARAM)NULL, "MatchEmailOrDomainName");
  79. // This validates that it is a good email name
  80. lstrcpyn(szDomainMat, szPattern, MAX_INTERNET_NAME + 1);
  81. szPattern = szDomainMat;
  82. pszPatternDomain = strchr(szDomainMat, '@');
  83. // See if we have an email wildcard at the left
  84. if (*szPattern == '*')
  85. {
  86. DebugTrace((LPARAM)NULL, "We have a left wildcard");
  87. fEmailWildMat = TRUE;
  88. szPattern++;
  89. wmEmailWildMatMode = WMOD_WILDCARD_LEFT;
  90. }
  91. // Get the domain pointer
  92. if (szEmailDomain)
  93. {
  94. dwEmailLen = (DWORD)(szEmailDomain - szEmail);
  95. *szEmailDomain++ = '\0';
  96. dwDomainLen = lstrlen(szEmailDomain);
  97. }
  98. else
  99. dwEmailLen = lstrlen(szEmail);
  100. // Validate that the lengths of szEmail and szEmailDomain will not
  101. // overflow our buffers
  102. if (dwEmailLen > MAX_INTERNET_NAME ||
  103. dwDomainLen > MAX_INTERNET_NAME)
  104. {
  105. hrRes = E_INVALIDARG;
  106. goto Cleanup;
  107. }
  108. if (pszPatternDomain)
  109. {
  110. dwEmailStemLen = (DWORD)(pszPatternDomain - szPattern);
  111. *pszPatternDomain++ = '\0';
  112. dwDomainStemLen = lstrlen(pszPatternDomain);
  113. if (*pszPatternDomain == '*')
  114. {
  115. fDomainWildMat = TRUE;
  116. dwDomainStemLen--;
  117. pszPatternDomain++;
  118. }
  119. }
  120. else
  121. dwEmailStemLen = lstrlen(szPattern);
  122. // See if we have an email wildcard at the right
  123. if (dwEmailStemLen &&
  124. *(szPattern + dwEmailStemLen - 1) == '*')
  125. {
  126. DebugTrace((LPARAM)NULL, "We have a right wildcard");
  127. szPattern[--dwEmailStemLen] = '\0';
  128. if (!fEmailWildMat)
  129. {
  130. // It has no left wildcard, so it is a right-only wildcard
  131. fEmailWildMat = TRUE;
  132. wmEmailWildMatMode = WMOD_WILDCARD_RIGHT;
  133. }
  134. else
  135. wmEmailWildMatMode = WMOD_WILDCARD_BOTH;
  136. }
  137. // Make sure there are no more wildcards embedded
  138. for (i = 0; i < dwEmailStemLen; i++)
  139. if (szPattern[i] == '*')
  140. {
  141. hrRes = ERROR_INVALID_PARAMETER;
  142. goto Cleanup;
  143. }
  144. for (i = 0; i < dwDomainStemLen; i++)
  145. if (pszPatternDomain[i] == '*')
  146. {
  147. hrRes = ERROR_INVALID_PARAMETER;
  148. goto Cleanup;
  149. }
  150. DebugTrace((LPARAM)NULL, "Email = <%s>, Domain = <%s>",
  151. szEmail, szEmailDomain?szEmailDomain:"none");
  152. DebugTrace((LPARAM)NULL, "Email = <%s>, Domain = <%s>",
  153. szPattern, pszPatternDomain?pszPatternDomain:"none");
  154. // OK, now eliminate by length
  155. if (dwEmailLen < dwEmailStemLen)
  156. {
  157. DebugTrace((LPARAM)NULL, "Email too short to match");
  158. hrRes = S_FALSE;
  159. goto Cleanup;
  160. }
  161. else
  162. {
  163. if (fEmailWildMat)
  164. {
  165. CHAR szPatternLower[MAX_INTERNET_NAME + 1];
  166. CHAR szEmailLower[MAX_INTERNET_NAME + 1];
  167. _ASSERT(wmEmailWildMatMode != WMOD_INVALID);
  168. _ASSERT(wmEmailWildMatMode < WMOD_WILDCARD_MAX);
  169. // Do the right thing based on the wildcard mode
  170. switch (wmEmailWildMatMode)
  171. {
  172. case WMOD_WILDCARD_LEFT:
  173. if (lstrcmpi(szPattern, szEmail + (dwEmailLen - dwEmailStemLen)))
  174. {
  175. DebugTrace((LPARAM)NULL, "Left email wildcard mismatch");
  176. hrRes = S_FALSE;
  177. goto Cleanup;
  178. }
  179. break;
  180. case WMOD_WILDCARD_RIGHT:
  181. pStringLower(szEmail, szEmailLower);
  182. pStringLower(szPattern, szPatternLower);
  183. if (strstr(szEmail, szPattern) != szEmail)
  184. {
  185. DebugTrace((LPARAM)NULL, "Right email wildcard mismatch");
  186. hrRes = S_FALSE;
  187. goto Cleanup;
  188. }
  189. break;
  190. case WMOD_WILDCARD_BOTH:
  191. pStringLower(szEmail, szEmailLower);
  192. pStringLower(szPattern, szPatternLower);
  193. if (strstr(szEmail, szPattern) == NULL)
  194. {
  195. DebugTrace((LPARAM)NULL, "Left and Right email wildcard mismatch");
  196. hrRes = S_FALSE;
  197. goto Cleanup;
  198. }
  199. break;
  200. }
  201. }
  202. else
  203. {
  204. if ((dwEmailLen != dwEmailStemLen) ||
  205. (lstrcmpi(szPattern, szEmail)))
  206. {
  207. DebugTrace((LPARAM)NULL, "Exact email match failed");
  208. hrRes = S_FALSE;
  209. goto Cleanup;
  210. }
  211. }
  212. }
  213. // We are matching the domain pattern
  214. if (pszPatternDomain)
  215. {
  216. if (!szEmailDomain)
  217. {
  218. DebugTrace((LPARAM)NULL, "No email domain");
  219. hrRes = S_FALSE;
  220. goto Cleanup;
  221. }
  222. if (dwDomainLen < dwDomainStemLen)
  223. {
  224. DebugTrace((LPARAM)NULL, "Domain too short to match");
  225. hrRes = S_FALSE;
  226. goto Cleanup;
  227. }
  228. else
  229. {
  230. if (fDomainWildMat)
  231. {
  232. if (lstrcmpi(pszPatternDomain,
  233. szEmailDomain + (dwDomainLen - dwDomainStemLen)))
  234. {
  235. DebugTrace((LPARAM)NULL, "Left domain wildcard mismatch");
  236. hrRes = S_FALSE;
  237. goto Cleanup;
  238. }
  239. }
  240. else
  241. {
  242. if ((dwDomainLen != dwDomainStemLen) ||
  243. (lstrcmpi(pszPatternDomain, szEmailDomain)))
  244. {
  245. DebugTrace((LPARAM)NULL, "Exact domain match failed");
  246. hrRes = S_FALSE;
  247. goto Cleanup;
  248. }
  249. }
  250. }
  251. }
  252. else
  253. hrRes = S_OK;
  254. Cleanup:
  255. TraceFunctLeaveEx((LPARAM)NULL);
  256. return(hrRes);
  257. }