|
|
/*++
Copyright (c) 1994-1999 Microsoft Corporation
Module Name :
strvalid.cpp
Abstract:
String Functions
Author:
Aaron Lee (aaronl)
Project:
Internet Services Manager
Revision History:
--*/
//
// Include Files
//
#include "stdafx.h"
#include "common.h"
#include "iisdebug.h"
#include <pudebug.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__; #endif
#define new DEBUG_NEW
//
// Procedure removes all characters in the second string from the first one.
//
INT RemoveChars(LPTSTR pszStr,LPTSTR pszRemoved) { INT iCharsRemovedCount = 0; INT iOrgStringLength = _tcslen(pszStr); INT cbRemoved = _tcslen(pszRemoved); INT iSrc, iDest; for (iSrc = iDest = 0; pszStr[iSrc]; iSrc++, iDest++) { // Check if this char is the in the list of stuf
// we are supposed to remove.
// if it is then just set iSrc to iSrc +1
#ifdef UNICODE
while (wmemchr(pszRemoved, pszStr[iSrc], cbRemoved)) #else
while (memchr(pszRemoved, pszStr[iSrc], cbRemoved)) #endif
{ iCharsRemovedCount++; iSrc++; }
// copy the character to itself
pszStr[iDest] = pszStr[iSrc]; }
// Cut off the left over strings
// which we didn't erase. but need to.
if (iCharsRemovedCount >= 0){pszStr[iOrgStringLength - iCharsRemovedCount]= '\0';}
return iDest - 1; }
BOOL IsContainInvalidChars(LPCTSTR szUncOrDirOrFilePart,LPCTSTR szListOfInvalidChars) { LPTSTR psz = (LPTSTR) szUncOrDirOrFilePart;
if (NULL == psz) return FALSE;
if (NULL == szListOfInvalidChars) return FALSE; while (*psz) { // Check if this characters is in the "bad" set.
if (_tcschr(szListOfInvalidChars,*psz)) { DebugTrace(_T("Path:Contains bad character '%c'"),*psz); return TRUE; } psz = ::CharNext(psz); }
return FALSE; } // This character set is invalid for:
// 1. Anything in a UNC path (includes servername,servershare,path,dir)
// 2. Anything in the dir part of the path (doesn't include drive part -- obviously c: -- includes a colon)
// 3. Anything in the filepart of the path
BOOL IsContainInvalidChars(LPCTSTR szUncOrDirOrFilePart) { return IsContainInvalidChars(szUncOrDirOrFilePart,_T(":|<>/*?\t\r\n")); }
BOOL IsContainInvalidCharsUNC(LPCTSTR lpFullFileNamePath) { return IsContainInvalidChars(lpFullFileNamePath); }
BOOL IsContainInvalidCharsAfterDrivePart(LPCTSTR lpFullFileNamePath) { TCHAR szPath_only[_MAX_PATH]; _tsplitpath(lpFullFileNamePath, NULL, szPath_only, NULL, NULL); if (szPath_only) { return IsContainInvalidChars(szPath_only); } return FALSE; }
BOOL IsContainInvalidCharsFilePart(LPCTSTR szFilenameOnly) { return IsContainInvalidChars(szFilenameOnly); }
BOOL IsDirPartExist(LPCTSTR lpFullFileNamePath) { TCHAR szDrive_only[_MAX_DRIVE]; TCHAR szPath_only[_MAX_PATH]; TCHAR szTemp[_MAX_PATH]; _tsplitpath(lpFullFileNamePath, szDrive_only, szPath_only, NULL, NULL);
// Get the Dirpart and see if it exists
_tcscpy(szTemp,szDrive_only); _tcscat(szTemp,szPath_only);
// Check if it's a directory
if (PathIsDirectory(szTemp)) { // it's an existing valid directory.
return TRUE; }
return FALSE; }
// bForFullFilePath = TRUE, if for something like \\servername\servershare\mydir\myfile.txt
// bForFullFilePath = FALSE, if for something like \\servername\servershare\mydir
BOOL IsValidUNCSpecialCases(LPCTSTR path,BOOL bLocal,BOOL bForFullFilePath) { BOOL bReturn = TRUE; CString csPathMunged = path; TCHAR * pszRoot = NULL;
if (!PathIsUNC(csPathMunged)) { bReturn = FALSE; goto IsValidUNCSpecialCases_Exit; }
if (PathIsUNCServer(csPathMunged)) { bReturn = TRUE; goto IsValidUNCSpecialCases_Exit; }
if (PathIsUNCServerShare(csPathMunged)) { bReturn = TRUE; goto IsValidUNCSpecialCases_Exit; } // From this point on.
// it is likely
// \\servername\servershare\somepath
// \\servername\servershare\somepath\somefilename.txt
// looking for an invalid UNC...
// Test for something lame like \\servername\\dir
// add enough space for an extra "\" at the beginning.
pszRoot = (TCHAR *) LocalAlloc(LPTR, ((_tcslen(csPathMunged)+2) * sizeof(TCHAR))); if (pszRoot) { // Add an extra "\" at the beginning.
_tcscpy(pszRoot,_T("\\")); _tcscat(pszRoot,csPathMunged);
// for some reason a UNC like this: \\\servername\dir
// will be valid for PathIsUNCServer.
// but a UNC like this: \\\\servername\dir will be invalid
// we want to ensure that \\\servername\dir is invalid
// that's why we added an extra "\"
if (PathStripToRoot(pszRoot)) { // if we get back just the \\server name
// then we have an invalid path.
// we're supposed to get back \\servername\servershare
if (PathIsUNCServer(pszRoot)) { bReturn = FALSE; DebugTrace(_T("Path:Bad UNC path")); goto IsValidUNCSpecialCases_Exit; } }
// We have \\servername\Servershare now...
if (bForFullFilePath) { // set it back to the real path without the extra "\"
_tcscpy(pszRoot,csPathMunged);
if (PathStripToRoot(pszRoot)) { // if we get back just the \\server name
// then we have an invalid path.
// we're supposed to get back \\servername\servershare
if (PathIsUNCServer(pszRoot)) { bReturn = FALSE; DebugTrace(_T("Path:Bad UNC path")); goto IsValidUNCSpecialCases_Exit; } else { _tcscpy(pszRoot,csPathMunged);
// it's a sharename.
// let's check if that is valid even...
TCHAR * pszAfterRoot = NULL; pszAfterRoot = PathSkipRoot(pszRoot);
if (pszAfterRoot) { if (0 == _tcslen(pszAfterRoot)) { if (bForFullFilePath) { // don't accept something like "\\servername\fileshare\"
bReturn = FALSE; DebugTrace(_T("Path:Bad UNC path:no accept \\\\s\\f\\ (ending slash)")); goto IsValidUNCSpecialCases_Exit; } } else if (0 == _tcsicmp(pszAfterRoot,_T("."))) { // don't accept something like "\\servername\fileshare\."
bReturn = FALSE; DebugTrace(_T("Path:Bad UNC path:no accept \\\\s\\f\\.")); goto IsValidUNCSpecialCases_Exit; } else { // otherwise it's probably
// \\servername\servershare\somedir
// \\servername\servershare\somedir\somefilename.txt
} } } } } }
IsValidUNCSpecialCases_Exit: if (pszRoot){LocalFree(pszRoot);} return bReturn; }
// return 0 on success
// error code on failure
FILERESULT MyValidatePath(LPCTSTR path,BOOL bLocal,INT iPathTypeWanted,DWORD dwAllowedFlags,DWORD dwCharSetFlags) { FILERESULT dwReturn = SEVERITY_SUCCESS; CString csPathMunged = path; CComBSTR bstrTempString;
// verify all parameters are filled in...
if (iPathTypeWanted != CHKPATH_WANT_FILE && iPathTypeWanted != CHKPATH_WANT_DIR) { return E_INVALIDARG; } if (dwAllowedFlags > CHKPATH_ALLOW_MAX) { return E_INVALIDARG; } if (dwCharSetFlags < CHKPATH_CHARSET_GENERAL || dwCharSetFlags > CHKPATH_CHARSET_MAX) { return E_INVALIDARG; }
// ------------
// length check
// ------------
{ dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_LENGTH,CHKPATH_FAIL_INVALID_EMPTY);
// check if it's empty
if (path == NULL || *path == 0) { dwReturn |= CHKPATH_FAIL_INVALID_EMPTY; DebugTrace(_T("Path:Empty")); goto MyValidatePath_Exit; }
// check if it's empty
if (0 == _tcslen(path)) { dwReturn |= CHKPATH_FAIL_INVALID_EMPTY; DebugTrace(_T("Path:Empty")); goto MyValidatePath_Exit; }
// check length
if (_tcslen(path) >= 256) { dwReturn |= CHKPATH_FAIL_INVALID_TOO_LONG; // it's empty, please specify something!
DebugTrace(_T("Path:too long")); goto MyValidatePath_Exit; }
// length check passes
dwReturn = SEVERITY_SUCCESS; }
// ------------------------
// Invalid characters check
// ------------------------
{ dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_CHARSET,CHKPATH_FAIL_INVALID_CHARSET_GENERAL);
// check for invalid characters...
bstrTempString = _T("\t\r\n"); if (IS_FLAG_SET(dwCharSetFlags,CHKPATH_CHARSET_GENERAL)) { bstrTempString = CHKPATH_INVALID_CHARSET_GENERAL; } if (IS_FLAG_SET(dwCharSetFlags,CHKPATH_CHARSET_GENERAL_NO_COMMA)) { // user wants to make sure that comma is an invalid entry
bstrTempString = bstrTempString + CHKPATH_INVALID_CHARSET_COMMA; } if (IS_FLAG_SET(dwCharSetFlags,CHKPATH_CHARSET_GENERAL_ALLOW_QUESTION)) { // user wants to allow Question marks...
RemoveChars((LPTSTR) bstrTempString,CHKPATH_INVALID_CHARSET_QUESTION); } if (IsContainInvalidChars(path,bstrTempString)) { dwReturn |= CHKPATH_FAIL_INVALID_CHARSET_GENERAL; DebugTrace(_T("Path:invalid chars")); goto MyValidatePath_Exit; }
// invalid chars check passes
dwReturn = SEVERITY_SUCCESS; }
// -------------------------------------------------------------
// Before we do anything we need to see if it's a "special" path
//
// Everything after this function must validate against csPathMunged...
// this is because GetSpecialPathRealPath could have munged it...
// -------------------------------------------------------------
csPathMunged = path; #ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS
GetSpecialPathRealPath(0,path,csPathMunged); #endif
// ------------------------
// Do we allow device type paths
// \\.\myfile.txt
// ------------------------
if (IsDevicePath(csPathMunged)) { if (IS_FLAG_SET(dwAllowedFlags,CHKPATH_ALLOW_DEVICE_PATH)) { // user allows device path
// Do we want to verify it further??
dwReturn = SEVERITY_SUCCESS; DebugTrace(_T("Path:accept device path")); } else { // user won't allow device path
// so return failure
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_DEVICE_PATH); DebugTrace(_T("Path:no accept device path")); } goto MyValidatePath_Exit; }
// ------------------------
// Do we allow device relative paths
// ..\testing\test.txt
// ------------------------
if (PathIsRelative(csPathMunged)) { if (IS_FLAG_SET(dwAllowedFlags,CHKPATH_ALLOW_RELATIVE_PATH)) { // we have a relative path...
// Check to see if it is valid...
// BUGBUG:aaronl: do more work here...
dwReturn = SEVERITY_SUCCESS; DebugTrace(_T("Path:accept relative path")); } else { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_RELATIVE_PATH); DebugTrace(_T("Path:no accept relative path")); } goto MyValidatePath_Exit; }
// -------------------------------------------------------------
// UNC Validation
// -------------------------------------------------------------
if (PathIsUNC(csPathMunged)) { // ------------------------
// Do we allow UNC type paths at all?
// \\servername
// \\servername\servershare
// \\servername\servershare\dir
// \\servername\servershare\dir\filename.txt
// ------------------------
if (!IS_FLAG_SET(dwAllowedFlags,CHKPATH_ALLOW_UNC_PATH)) { // We are not allowing UNC paths...
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_UNC_PATH); DebugTrace(_T("Path:no accept UNC path")); goto MyValidatePath_Exit; }
// ------------------------
// Do we allow servername only?
// \\servername
// ------------------------
if (PathIsUNCServer(csPathMunged)) { if (IS_FLAG_SET(dwAllowedFlags,CHKPATH_ALLOW_UNC_SERVERNAME_ONLY)) { dwReturn = SEVERITY_SUCCESS; DebugTrace(_T("Path:accept only servername")); } else { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_UNC_SERVERNAME); DebugTrace(_T("Path:no accept only servername")); } goto MyValidatePath_Exit; }
// ------------------------
// Do we allow servershare only?
// \\servername\servershare
// ------------------------
if (PathIsUNCServerShare(csPathMunged)) { if (IS_FLAG_SET(dwAllowedFlags,CHKPATH_ALLOW_UNC_SERVERSHARE_ONLY)) { dwReturn = SEVERITY_SUCCESS; DebugTrace(_T("Path:accept only servershare")); } else { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_UNC_SERVERSHARE); DebugTrace(_T("Path:no accept only servershare")); } goto MyValidatePath_Exit; }
// Check for invalid chars in UNC path
if (IsContainInvalidCharsUNC(csPathMunged)) { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_CHARSET,CHKPATH_FAIL_INVALID_CHARSET_FOR_UNC); DebugTrace(_T("Path:Bad UNC share contains ':'")); goto MyValidatePath_Exit; }
// ------------------------
// Check for special case invalid UNC paths...
// \\servername\servershare\ // \\servername\servershare\.
// ------------------------
BOOL bWantFilePart = FALSE; if (iPathTypeWanted == CHKPATH_WANT_FILE) { bWantFilePart = TRUE; } if (!IsValidUNCSpecialCases(csPathMunged,bLocal,bWantFilePart)) { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_PARTS,CHKPATH_FAIL_INVALID_BAD_UNC_PART); DebugTrace(_T("Path:Bad UNC share")); goto MyValidatePath_Exit; }
// this function is UNC friendly
if (bLocal) { if (PathIsDirectory(csPathMunged)) { if (iPathTypeWanted == CHKPATH_WANT_FILE) { // it is a valid directory...but we don't want that
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_DIR_PATH); DebugTrace(_T("Path:PathIsDirectory:DIR specified, should be filename")); goto MyValidatePath_Exit; } } else { // path is not directory
// check if that is what they wanted.
if (iPathTypeWanted == CHKPATH_WANT_DIR) { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_DIR_NOT_EXIST); DebugTrace(_T("Path:PathIsDirectory:DIR not exist")); // the directory doesn't exist...
goto MyValidatePath_Exit; } } }
// if we are here, then we passed all the above ways that we could figure
// out if this is an invalid UNC.
// now we just need to determine if it's what the user wants!
// is there anyway we can verify that is is a filename
// and not a dir???
goto MyValidatePath_Exit; }
// -------------------------------------------------------------
// Regular filepath Validation
// -------------------------------------------------------------
// ensure that we have a valid drive path...
// "c:myfile.txt" is not valid!
// we have to have all parts
// Not -- just directory paths, we need filename part
// check if it has these 3 parts "c:\"
if (!IsFullyQualifiedPath(csPathMunged)) { // Missing drive part
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_PARTS,CHKPATH_FAIL_INVALID_BAD_DRIVE_PART); DebugTrace(_T("Path:IsFullyQualifiedPath:Bad Drive path")); goto MyValidatePath_Exit; }
// check if dir part contains invalid chars
if (IsContainInvalidCharsAfterDrivePart(csPathMunged)) { // Bad path portion
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_CHARSET,CHKPATH_FAIL_INVALID_CHARSET_FOR_DIR); DebugTrace(_T("Path:IsContainInvalidCharsAfterDrivePart:Bad Dir path")); goto MyValidatePath_Exit; }
// check if specified path, has a filename part
if (iPathTypeWanted == CHKPATH_WANT_FILE) { TCHAR szFullPath[_MAX_PATH]; LPTSTR pFilePart = NULL; if (0 == GetFullPathName(csPathMunged, _MAX_PATH, szFullPath, &pFilePart)) { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_PARTS,CHKPATH_FAIL_INVALID_BAD_PATH); DebugTrace(_T("Path:GetFullPathName FAILED")); goto MyValidatePath_Exit; } if (NULL == pFilePart) { // Missing filename
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_PARTS,CHKPATH_FAIL_INVALID_BAD_FILE_PART); DebugTrace(_T("Path:GetFullPathName missing filename")); goto MyValidatePath_Exit; } else { // Check if the file part contains a ":"
// since this is invalid for a filename...
// Check if it contains an invalid character like ':'
if (IsContainInvalidCharsFilePart(pFilePart)) { // contains a bad character
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_CHARSET,CHKPATH_FAIL_INVALID_CHARSET_FOR_FILE); DebugTrace(_T("Path:filename contains bad char ':'")); goto MyValidatePath_Exit; } } }
// check if it's a directory
if (bLocal) { // ------------------------------------------------
// check for a filename at the end
// the user wants a path with a filename at the end
// ------------------------------------------------
if (iPathTypeWanted == CHKPATH_WANT_FILE) { // Check if it's a directory
if (PathIsDirectory(csPathMunged)) { // it is a valid directory...but we don't want that
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_DIR_PATH); DebugTrace(_T("Path:PathIsDirectory:DIR specified, should be filename!")); goto MyValidatePath_Exit; }
// strip off the filename part and
// check if the user specified a valid directory in the dir portion
if (IsContainInvalidCharsAfterDrivePart(csPathMunged)) { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_PARTS,CHKPATH_FAIL_INVALID_BAD_DIR_PART); DebugTrace(_T("Path:DirectoryIsInvalid:Bad Dir Part")); goto MyValidatePath_Exit; }
if (FALSE == IsDirPartExist(csPathMunged)) { // it's not a directory that exists...
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_DIR_NOT_EXIST); DebugTrace(_T("Path:Dir Part doesnt exist")); goto MyValidatePath_Exit; }
{ // check if the filename part is valid
// dont' accept c:\\\a.dll, or c:\\a.dll
TCHAR * pszAfterRoot = NULL; pszAfterRoot = PathSkipRoot(csPathMunged); if (pszAfterRoot) { // check if there are any \ in the beginning.
if ( pszAfterRoot[0] == '\\' ) { dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_INVALID_PARTS,CHKPATH_FAIL_INVALID_BAD_FILE_PART); DebugTrace(_T("Path:bad filename:%s"),pszAfterRoot); goto MyValidatePath_Exit; } } }
/*
if (!PathFileExists(csPathMunged)) { // err, file does not exists
} */ } else { // ------------------------------------------------
// check for dir
// the user wants a dir with no filename
// ------------------------------------------------
// Check if it's a directory
if (!PathIsDirectory(csPathMunged)) { // it's not a directory that exists...
dwReturn = MAKE_FILERESULT(SEVERITY_ERROR,CHKPATH_FAIL_NOT_ALLOWED,CHKPATH_FAIL_NOT_ALLOWED_DIR_NOT_EXIST); DebugTrace(_T("Path:DirectoryIsInvalid:Bad Dir Part")); goto MyValidatePath_Exit; } } }
MyValidatePath_Exit: DebugTrace(_T("MyValidatePath(%s)=0x%x:"),path,dwReturn); if (IS_FLAG_SET(dwReturn,CHKPATH_FAIL_INVALID_LENGTH)) { DebugTrace(_T("CHKPATH_FAIL_INVALID_LENGTH\r\n")); } if (IS_FLAG_SET(dwReturn,CHKPATH_FAIL_INVALID_CHARSET)) { DebugTrace(_T("CHKPATH_FAIL_INVALID_CHARSET\r\n")); } if (IS_FLAG_SET(dwReturn,CHKPATH_FAIL_INVALID_PARTS)) { DebugTrace(_T("CHKPATH_FAIL_INVALID_PARTS\r\n")); } if (IS_FLAG_SET(dwReturn,CHKPATH_FAIL_NOT_ALLOWED)) { DebugTrace(_T("CHKPATH_FAIL_NOT_ALLOWED\r\n")); } return dwReturn; }
|