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.

163 lines
5.1 KiB

  1. /*
  2. * S E C U R I T Y . C P P
  3. *
  4. * Url security checks. While these would seem to only apply to HttpEXT,
  5. * all impls. that care about ASP execution should really think about this.
  6. *
  7. * Bits stolen from the IIS5 project 'iis5\infocom\cache2\filemisc.cxx' and
  8. * cleaned up to fit in with the DAV sources.
  9. *
  10. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  11. */
  12. #include "_davprs.h"
  13. // This function takes a suspected NT/Win95 short filename and checks
  14. // if there's an equivalent long filename.
  15. //
  16. // For example, c:\foobar\ABCDEF~1.ABC is the same as
  17. // c:\foobar\abcdefghijklmnop.abc.
  18. //
  19. // If there is an equivalent, we need to FAIL this path, because our metabase
  20. // will NOT have the correct values listed under the short paths!
  21. // If there is no equivalent, this path can be allowed through, because it
  22. // might be a real storage entitiy (not an alias for a real storage entity).
  23. //
  24. // NOTE: This function should be called unimpersonated - the FindFirstFile()
  25. // must be called in the system context since most systems have traverse
  26. // checking turned off - except for the UNC case where we must be impersonated
  27. // to get network access.
  28. //
  29. SCODE __fastcall
  30. ScCheckIfShortFileName (
  31. /* [in] */ LPCWSTR pwszPath,
  32. /* [in] */ const HANDLE hitUser)
  33. {
  34. WIN32_FIND_DATAW fd;
  35. LPCWSTR pwsz;
  36. BOOL fUNC = FALSE;
  37. // Skip forward to find the first '~'
  38. //
  39. if (NULL == (pwsz = wcschr(pwszPath, L'~')))
  40. return S_OK;
  41. //$ REVIEW: this is not sufficient for DavEX, but it is unclear that
  42. // this function applies there. Certainly the FindFirstFile() call
  43. // will fail at this time.
  44. //
  45. fUNC = (*pwszPath == L'\\');
  46. Assert (!fUNC || (NULL != hitUser));
  47. // We actually need to loop in case multiple '~' appear in the filename
  48. //
  49. do
  50. {
  51. // At this point, pwsz should be pointing to the '~'
  52. //
  53. Assert (L'~' == *pwsz);
  54. // Is the next char a digit?
  55. //
  56. pwsz++;
  57. if ((*pwsz >= L'0') && (*pwsz <= L'9'))
  58. {
  59. WCHAR wszTmp[MAX_PATH];
  60. const WCHAR * pwchEndSeg;
  61. const WCHAR * pwchBeginSeg;
  62. HANDLE hFind;
  63. // Isolate the path up to the segment with the
  64. // '~' and do the FindFirstFile with that path
  65. //
  66. pwchEndSeg = wcschr (pwsz, L'\\');
  67. if (!pwchEndSeg)
  68. {
  69. pwchEndSeg = pwsz + wcslen (pwsz);
  70. }
  71. // If the string is beyond MAX_PATH then we fail it.
  72. // urls this long don't need to have '~N' in them.
  73. //
  74. // Also check that our buffer is big enough to handle anything
  75. // that gets through this check.
  76. //
  77. // NOTE: We are assuming that other code outside this function
  78. // will catch paths that are larger than MAX_PATH and FAIL them.
  79. //
  80. //$ REVIEW: the MAX_PATH restriction is very important because
  81. // the call to FindFirstFile() will fail if the path is larger
  82. // than MAX_PATH. Should we ever decide to support larger paths
  83. // in HttpEXT, this code will have to change.
  84. //
  85. Assert (MAX_PATH == CElems(wszTmp));
  86. if ((pwchEndSeg - pwszPath) >= MAX_PATH)
  87. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  88. // Make a copy of the string up to this point in the path
  89. //
  90. wcsncpy (wszTmp, pwszPath, pwchEndSeg - pwszPath);
  91. wszTmp[pwchEndSeg - pwszPath] = 0;
  92. // If we are not accessing a unc, then we need to revert
  93. // for our call to FindFirstFile() -- see comment above.
  94. //
  95. if (!fUNC)
  96. {
  97. safe_revert (const_cast<HANDLE>(hitUser));
  98. hFind = FindFirstFileW (wszTmp, &fd);
  99. }
  100. else
  101. hFind = FindFirstFileW (wszTmp, &fd);
  102. if (hFind == INVALID_HANDLE_VALUE)
  103. {
  104. // If the FindFirstFile() fails to find the file then
  105. // the filename cannot be a short name.
  106. //
  107. DWORD dw = GetLastError();
  108. if ((ERROR_FILE_NOT_FOUND != dw) && (ERROR_PATH_NOT_FOUND != dw))
  109. return HRESULT_FROM_WIN32(dw);
  110. return S_OK;
  111. }
  112. // Make sure the find context gets closed.
  113. //
  114. FindClose (hFind);
  115. // Isolate the last segment of the string which should be
  116. // the potential short name equivalency
  117. //
  118. pwchBeginSeg = wcsrchr (wszTmp, '\\');
  119. Assert (pwchBeginSeg);
  120. pwchBeginSeg++;
  121. // If the last segment doesn't match the long name then
  122. // this is the short name version (alias) of the path -- so
  123. // fail this function.
  124. //
  125. if (_wcsicmp (fd.cFileName, pwchBeginSeg))
  126. {
  127. DebugTrace ("Dav: Url: refers to shortname for file\n");
  128. Assert (!_wcsicmp (fd.cAlternateFileName, pwchBeginSeg));
  129. return E_DAV_SHORT_FILENAME;
  130. }
  131. }
  132. } while (NULL != (pwsz = wcschr (pwsz, L'~')));
  133. return S_OK;
  134. }
  135. SCODE __fastcall
  136. ScCheckForAltFileStream (
  137. /* [in] */ LPCWSTR pwszPath)
  138. {
  139. // Avoid the infamous ::$DATA bug
  140. //
  141. if (wcsstr (pwszPath, L"::"))
  142. return E_DAV_ALT_FILESTREAM;
  143. return S_OK;
  144. }