Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
373
third_party/FreeRDP/winpr/libwinpr/file/pattern.c
vendored
Normal file
373
third_party/FreeRDP/winpr/libwinpr/file/pattern.c
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* File Functions
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/handle.h>
|
||||
|
||||
#include <winpr/file.h>
|
||||
|
||||
#ifdef WINPR_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef WINPR_HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("file")
|
||||
|
||||
/**
|
||||
* File System Behavior in the Microsoft Windows Environment:
|
||||
* http://download.microsoft.com/download/4/3/8/43889780-8d45-4b2e-9d3a-c696a890309f/File%20System%20Behavior%20Overview.pdf
|
||||
*/
|
||||
|
||||
LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags)
|
||||
{
|
||||
LPSTR lpWildcard = nullptr;
|
||||
*pFlags = 0;
|
||||
lpWildcard = strpbrk(lpPattern, "*?~");
|
||||
|
||||
if (lpWildcard)
|
||||
{
|
||||
if (*lpWildcard == '*')
|
||||
{
|
||||
*pFlags = WILDCARD_STAR;
|
||||
return lpWildcard;
|
||||
}
|
||||
else if (*lpWildcard == '?')
|
||||
{
|
||||
*pFlags = WILDCARD_QM;
|
||||
return lpWildcard;
|
||||
}
|
||||
else if (*lpWildcard == '~')
|
||||
{
|
||||
if (lpWildcard[1] == '*')
|
||||
{
|
||||
*pFlags = WILDCARD_DOS_STAR;
|
||||
return lpWildcard;
|
||||
}
|
||||
else if (lpWildcard[1] == '?')
|
||||
{
|
||||
*pFlags = WILDCARD_DOS_QM;
|
||||
return lpWildcard;
|
||||
}
|
||||
else if (lpWildcard[1] == '.')
|
||||
{
|
||||
*pFlags = WILDCARD_DOS_DOT;
|
||||
return lpWildcard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, LPCSTR lpX,
|
||||
size_t cchX, LPCSTR lpY, size_t cchY, LPCSTR lpWildcard,
|
||||
LPCSTR* ppMatchEnd)
|
||||
{
|
||||
LPCSTR lpMatch = nullptr;
|
||||
|
||||
if (!lpFileName)
|
||||
return FALSE;
|
||||
|
||||
if (*lpWildcard == '*')
|
||||
{
|
||||
/*
|
||||
* S
|
||||
* <-----<
|
||||
* X | | e Y
|
||||
* X * Y == (0)----->-(1)->-----(2)-----(3)
|
||||
*/
|
||||
|
||||
/*
|
||||
* State 0: match 'X'
|
||||
*/
|
||||
if (_strnicmp(lpFileName, lpX, cchX) != 0)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* State 1: match 'S' or 'e'
|
||||
*
|
||||
* We use 'e' to transition to state 2
|
||||
*/
|
||||
|
||||
/**
|
||||
* State 2: match Y
|
||||
*/
|
||||
|
||||
if (cchY != 0)
|
||||
{
|
||||
/* TODO: case insensitive character search */
|
||||
lpMatch = strchr(&lpFileName[cchX], *lpY);
|
||||
|
||||
if (!lpMatch)
|
||||
return FALSE;
|
||||
|
||||
if (_strnicmp(lpMatch, lpY, cchY) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpMatch = &lpFileName[cchFileName];
|
||||
}
|
||||
|
||||
/**
|
||||
* State 3: final state
|
||||
*/
|
||||
*ppMatchEnd = &lpMatch[cchY];
|
||||
return TRUE;
|
||||
}
|
||||
else if (*lpWildcard == '?')
|
||||
{
|
||||
/**
|
||||
* X S Y
|
||||
* X ? Y == (0)---(1)---(2)---(3)
|
||||
*/
|
||||
|
||||
/*
|
||||
* State 0: match 'X'
|
||||
*/
|
||||
if (cchFileName < cchX)
|
||||
return FALSE;
|
||||
|
||||
if (_strnicmp(lpFileName, lpX, cchX) != 0)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* State 1: match 'S'
|
||||
*/
|
||||
|
||||
/**
|
||||
* State 2: match Y
|
||||
*/
|
||||
|
||||
if (cchY != 0)
|
||||
{
|
||||
/* TODO: case insensitive character search */
|
||||
lpMatch = strchr(&lpFileName[cchX + 1], *lpY);
|
||||
|
||||
if (!lpMatch)
|
||||
return FALSE;
|
||||
|
||||
if (_strnicmp(lpMatch, lpY, cchY) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((cchX + 1) > cchFileName)
|
||||
return FALSE;
|
||||
|
||||
lpMatch = &lpFileName[cchX + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* State 3: final state
|
||||
*/
|
||||
*ppMatchEnd = &lpMatch[cchY];
|
||||
return TRUE;
|
||||
}
|
||||
else if (*lpWildcard == '~')
|
||||
{
|
||||
WLog_ERR(TAG, "warning: unimplemented '~' pattern match");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern)
|
||||
{
|
||||
BOOL match = 0;
|
||||
LPCSTR lpTail = nullptr;
|
||||
size_t cchTail = 0;
|
||||
size_t cchPattern = 0;
|
||||
size_t cchFileName = 0;
|
||||
DWORD dwFlags = 0;
|
||||
DWORD dwNextFlags = 0;
|
||||
LPSTR lpWildcard = nullptr;
|
||||
LPSTR lpNextWildcard = nullptr;
|
||||
|
||||
/**
|
||||
* Wild Card Matching
|
||||
*
|
||||
* '*' matches 0 or more characters
|
||||
* '?' matches exactly one character
|
||||
*
|
||||
* '~*' DOS_STAR - matches 0 or more characters until encountering and matching final '.'
|
||||
*
|
||||
* '~?' DOS_QM - matches any single character, or upon encountering a period or end of name
|
||||
* string, advances the expression to the end of the set of contiguous DOS_QMs.
|
||||
*
|
||||
* '~.' DOS_DOT - matches either a '.' or zero characters beyond name string.
|
||||
*/
|
||||
|
||||
if (!lpPattern)
|
||||
return FALSE;
|
||||
|
||||
if (!lpFileName)
|
||||
return FALSE;
|
||||
|
||||
cchPattern = strlen(lpPattern);
|
||||
cchFileName = strlen(lpFileName);
|
||||
|
||||
/**
|
||||
* First and foremost the file system starts off name matching with the expression “*”.
|
||||
* If the expression contains a single wild card character ‘*’ all matches are satisfied
|
||||
* immediately. This is the most common wild card character used in Windows and expression
|
||||
* evaluation is optimized by looking for this character first.
|
||||
*/
|
||||
|
||||
if ((lpPattern[0] == '*') && (cchPattern == 1))
|
||||
return TRUE;
|
||||
|
||||
/**
|
||||
* Subsequently evaluation of the “*X” expression is performed. This is a case where
|
||||
* the expression starts off with a wild card character and contains some non-wild card
|
||||
* characters towards the tail end of the name. This is evaluated by making sure the
|
||||
* expression starts off with the character ‘*’ and does not contain any wildcards in
|
||||
* the latter part of the expression. The tail part of the expression beyond the first
|
||||
* character ‘*’ is matched against the file name at the end uppercasing each character
|
||||
* if necessary during the comparison.
|
||||
*/
|
||||
|
||||
if (lpPattern[0] == '*')
|
||||
{
|
||||
lpTail = &lpPattern[1];
|
||||
cchTail = strlen(lpTail);
|
||||
|
||||
if (!FilePatternFindNextWildcardA(lpTail, &dwFlags))
|
||||
{
|
||||
/* tail contains no wildcards */
|
||||
if (cchFileName < cchTail)
|
||||
return FALSE;
|
||||
|
||||
if (_stricmp(&lpFileName[cchFileName - cchTail], lpTail) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The remaining expressions are evaluated in a non deterministic
|
||||
* finite order as listed below, where:
|
||||
*
|
||||
* 'S' is any single character
|
||||
* 'S-.' is any single character except the final '.'
|
||||
* 'e' is a null character transition
|
||||
* 'EOF' is the end of the name string
|
||||
*
|
||||
* S
|
||||
* <-----<
|
||||
* X | | e Y
|
||||
* X * Y == (0)----->-(1)->-----(2)-----(3)
|
||||
*
|
||||
*
|
||||
* S-.
|
||||
* <-----<
|
||||
* X | | e Y
|
||||
* X ~* Y == (0)----->-(1)->-----(2)-----(3)
|
||||
*
|
||||
*
|
||||
* X S S Y
|
||||
* X ?? Y == (0)---(1)---(2)---(3)---(4)
|
||||
*
|
||||
*
|
||||
* X S-. S-. Y
|
||||
* X ~?~? == (0)---(1)-----(2)-----(3)---(4)
|
||||
* | |_______|
|
||||
* | ^ |
|
||||
* |_______________|
|
||||
* ^EOF of .^
|
||||
*
|
||||
*/
|
||||
lpWildcard = FilePatternFindNextWildcardA(lpPattern, &dwFlags);
|
||||
|
||||
if (lpWildcard)
|
||||
{
|
||||
LPCSTR lpX = nullptr;
|
||||
LPCSTR lpY = nullptr;
|
||||
size_t cchX = 0;
|
||||
size_t cchY = 0;
|
||||
LPCSTR lpMatchEnd = nullptr;
|
||||
LPCSTR lpSubPattern = nullptr;
|
||||
size_t cchSubPattern = 0;
|
||||
LPCSTR lpSubFileName = nullptr;
|
||||
size_t cchSubFileName = 0;
|
||||
size_t cchWildcard = 0;
|
||||
size_t cchNextWildcard = 0;
|
||||
cchSubPattern = cchPattern;
|
||||
lpSubPattern = lpPattern;
|
||||
cchSubFileName = cchFileName;
|
||||
lpSubFileName = lpFileName;
|
||||
cchWildcard = ((dwFlags & WILDCARD_DOS) ? 2 : 1);
|
||||
lpNextWildcard = FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
|
||||
|
||||
if (!lpNextWildcard)
|
||||
{
|
||||
lpX = lpSubPattern;
|
||||
cchX = WINPR_ASSERTING_INT_CAST(size_t, (lpWildcard - lpSubPattern));
|
||||
lpY = &lpSubPattern[cchX + cchWildcard];
|
||||
cchY = (cchSubPattern - WINPR_ASSERTING_INT_CAST(size_t, (lpY - lpSubPattern)));
|
||||
match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX, lpY,
|
||||
cchY, lpWildcard, &lpMatchEnd);
|
||||
return match;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (lpNextWildcard)
|
||||
{
|
||||
cchSubFileName =
|
||||
cchFileName - WINPR_ASSERTING_INT_CAST(size_t, (lpSubFileName - lpFileName));
|
||||
cchNextWildcard = ((dwNextFlags & WILDCARD_DOS) ? 2 : 1);
|
||||
lpX = lpSubPattern;
|
||||
cchX = WINPR_ASSERTING_INT_CAST(size_t, (lpWildcard - lpSubPattern));
|
||||
lpY = &lpSubPattern[cchX + cchWildcard];
|
||||
cchY =
|
||||
WINPR_ASSERTING_INT_CAST(size_t, (lpNextWildcard - lpWildcard)) - cchWildcard;
|
||||
match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX,
|
||||
lpY, cchY, lpWildcard, &lpMatchEnd);
|
||||
|
||||
if (!match)
|
||||
return FALSE;
|
||||
|
||||
lpSubFileName = lpMatchEnd;
|
||||
cchWildcard = cchNextWildcard;
|
||||
lpWildcard = lpNextWildcard;
|
||||
dwFlags = dwNextFlags;
|
||||
lpNextWildcard =
|
||||
FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no wildcard characters */
|
||||
if (_stricmp(lpFileName, lpPattern) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
Reference in New Issue
Block a user