/* * S E C U R I T Y . C P P * * Url security checks. While these would seem to only apply to HttpEXT, * all impls. that care about ASP execution should really think about this. * * Bits stolen from the IIS5 project 'iis5\infocom\cache2\filemisc.cxx' and * cleaned up to fit in with the DAV sources. * * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved */ #include "_davprs.h" // This function takes a suspected NT/Win95 short filename and checks // if there's an equivalent long filename. // // For example, c:\foobar\ABCDEF~1.ABC is the same as // c:\foobar\abcdefghijklmnop.abc. // // If there is an equivalent, we need to FAIL this path, because our metabase // will NOT have the correct values listed under the short paths! // If there is no equivalent, this path can be allowed through, because it // might be a real storage entitiy (not an alias for a real storage entity). // // NOTE: This function should be called unimpersonated - the FindFirstFile() // must be called in the system context since most systems have traverse // checking turned off - except for the UNC case where we must be impersonated // to get network access. // SCODE __fastcall ScCheckIfShortFileName ( /* [in] */ LPCWSTR pwszPath, /* [in] */ const HANDLE hitUser) { WIN32_FIND_DATAW fd; LPCWSTR pwsz; BOOL fUNC = FALSE; // Skip forward to find the first '~' // if (NULL == (pwsz = wcschr(pwszPath, L'~'))) return S_OK; //$ REVIEW: this is not sufficient for DavEX, but it is unclear that // this function applies there. Certainly the FindFirstFile() call // will fail at this time. // fUNC = (*pwszPath == L'\\'); Assert (!fUNC || (NULL != hitUser)); // We actually need to loop in case multiple '~' appear in the filename // do { // At this point, pwsz should be pointing to the '~' // Assert (L'~' == *pwsz); // Is the next char a digit? // pwsz++; if ((*pwsz >= L'0') && (*pwsz <= L'9')) { WCHAR wszTmp[MAX_PATH]; const WCHAR * pwchEndSeg; const WCHAR * pwchBeginSeg; HANDLE hFind; // Isolate the path up to the segment with the // '~' and do the FindFirstFile with that path // pwchEndSeg = wcschr (pwsz, L'\\'); if (!pwchEndSeg) { pwchEndSeg = pwsz + wcslen (pwsz); } // If the string is beyond MAX_PATH then we fail it. // urls this long don't need to have '~N' in them. // // Also check that our buffer is big enough to handle anything // that gets through this check. // // NOTE: We are assuming that other code outside this function // will catch paths that are larger than MAX_PATH and FAIL them. // //$ REVIEW: the MAX_PATH restriction is very important because // the call to FindFirstFile() will fail if the path is larger // than MAX_PATH. Should we ever decide to support larger paths // in HttpEXT, this code will have to change. // Assert (MAX_PATH == CElems(wszTmp)); if ((pwchEndSeg - pwszPath) >= MAX_PATH) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // Make a copy of the string up to this point in the path // wcsncpy (wszTmp, pwszPath, pwchEndSeg - pwszPath); wszTmp[pwchEndSeg - pwszPath] = 0; // If we are not accessing a unc, then we need to revert // for our call to FindFirstFile() -- see comment above. // if (!fUNC) { safe_revert (const_cast(hitUser)); hFind = FindFirstFileW (wszTmp, &fd); } else hFind = FindFirstFileW (wszTmp, &fd); if (hFind == INVALID_HANDLE_VALUE) { // If the FindFirstFile() fails to find the file then // the filename cannot be a short name. // DWORD dw = GetLastError(); if ((ERROR_FILE_NOT_FOUND != dw) && (ERROR_PATH_NOT_FOUND != dw)) return HRESULT_FROM_WIN32(dw); return S_OK; } // Make sure the find context gets closed. // FindClose (hFind); // Isolate the last segment of the string which should be // the potential short name equivalency // pwchBeginSeg = wcsrchr (wszTmp, '\\'); Assert (pwchBeginSeg); pwchBeginSeg++; // If the last segment doesn't match the long name then // this is the short name version (alias) of the path -- so // fail this function. // if (_wcsicmp (fd.cFileName, pwchBeginSeg)) { DebugTrace ("Dav: Url: refers to shortname for file\n"); Assert (!_wcsicmp (fd.cAlternateFileName, pwchBeginSeg)); return E_DAV_SHORT_FILENAME; } } } while (NULL != (pwsz = wcschr (pwsz, L'~'))); return S_OK; } SCODE __fastcall ScCheckForAltFileStream ( /* [in] */ LPCWSTR pwszPath) { // Avoid the infamous ::$DATA bug // if (wcsstr (pwszPath, L"::")) return E_DAV_ALT_FILESTREAM; return S_OK; }