📄 vroots.hpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: VROOTS.CPP
Abstract: Virtual roots handling mechanism.
--*/
typedef enum {
AUTH_PUBLIC = 0,
AUTH_USER = 1,
AUTH_ADMIN = 2,
AUTH_MAX = 99
}
AUTHLEVEL;
typedef struct {
int iURLLen;
PSTR pszURL;
int iPathLen;
PWSTR wszPath;
PSTR pszRedirectURL;
DWORD dwPermissions; // HSE_URL_xxx flags
AUTHLEVEL AuthLevel; // What level of auth is required to gain access to this page?
SCRIPT_TYPE ScriptType; // Does vroot physical path map to an ASP or ISAPI?
WCHAR *wszUserList; // List of users that have access to this page.
// Number of '/' (and '\\') chars in the vroot name, not counting initial '/' or last slash if no chars are after it.
// So '/a' has 0, /a/b has 1, /a/b/c and /a/b/c/ both have 2.
int iNumSlashes;
unsigned int fRootDir : 1; // When pointing to root of filesys, special case handeling is needed.
unsigned int fRedirect : 1; // TRUE if we should send a "302 redirect" response to client.
unsigned int fDirBrowse : 1; // Is directory browsing allowed?
unsigned int fNTLM : 1; // Will we do NTLM auth?
unsigned int fBasic : 1; // Will we do BASIC auth?
unsigned int fNegotiate : 1; // Will we do Negotiate auth?
}
VROOTINFO, *PVROOTINFO;
inline BOOL IsSlash(CHAR c) {
return ((c == '/') || (c == '\\'));
}
inline int CountSignificantSlashesInURL(PCSTR pszURL, int iURLLen) {
DWORD iSlashes = 0;
// Skip first char '/', and don't check last character for ending '/'.
for (int j = 1; j < iURLLen-1; j++) {
if (IsSlash(pszURL[j]))
iSlashes++;
}
return iSlashes;
}
// Used to split a URL and Path Translated apart for ISAPI/ASP scripts
inline void SetPathInfo(PSTR *ppszPathInfo,PSTR pszInputURL,int iURLLen) {
int iLen = strlen(pszInputURL+iURLLen) + 2;
// If we've mapped the virtual root "/" to a script, need an extra "/" for the path
// (normally we use the origial trailing "/", but in this case the "/" is the URL
*ppszPathInfo = MySzAllocA((iURLLen == 1) ? iLen + 1 : iLen);
if (! (*ppszPathInfo))
goto done;
if (iURLLen == 1) {
(*ppszPathInfo)[0] = '/';
memcpy( (*ppszPathInfo) +1, pszInputURL + iURLLen, iLen);
}
else
memcpy(*ppszPathInfo, pszInputURL + iURLLen, iLen);
done:
// URL shouldn't contain path info, break it apart
pszInputURL[iURLLen] = 0;
}
// We convert all '/' in URL to '\' in the filename just in case there's filesystems
// that are picky between / and \. This won't affect most cases because even if user
// enters a '\' in URL, browser will change it to a '/' before sending it across wire.
inline void ConvertSlashes(WCHAR *szPath) {
while (*szPath) {
if (*szPath == '/')
*szPath = '\\';
szPath++;
}
}
// Returns next occurence of either '/' or '\\'
inline PSTR GetNextSlash(PCSTR szString) {
const CHAR cszSlashes[] = {'/', '\\', '\0'};
return (PSTR)strpbrk(szString,cszSlashes);
}
class CVRoots {
int m_nVRoots;
PVROOTINFO m_pVRoots;
PVROOTINFO MatchVRoot(PCSTR pszInputURL, int iInputLen) {
int i;
// If there was an error on setting up the vroots, m_pVRoots = NULL.
if (!m_pVRoots)
return NULL;
int iInputSlashes = CountSignificantSlashesInURL(pszInputURL,iInputLen);
PCSTR szFirstUrlSlashInit = GetNextSlash(pszInputURL+1);
if (NULL == szFirstUrlSlashInit)
szFirstUrlSlashInit = strchr(pszInputURL,'\0');
for (i = 0; i < m_nVRoots; i++) {
int iLen = m_pVRoots[i].iURLLen;
PCSTR szFirstUrlSlash = szFirstUrlSlashInit;
// If this root maps to physical path "\", special case.
// In general we store pszURL without trailing "/", however we have
// to store trailing "/" for root directory.
if (m_pVRoots[i].fRootDir && iLen != 1)
iLen--;
// URL isn't long enough to possibly match the vroot
if (! (iLen && iInputLen >= iLen))
continue;
// If it's path '/', always match.
if (iLen == 1) {
DEBUGMSG(ZONE_VROOTS, (L"HTTPD: URL %a matched VRoot %a (path %s, perm=%d, auth=%d)\r\n",
pszInputURL, m_pVRoots[i].pszURL, m_pVRoots[i].wszPath, m_pVRoots[i].dwPermissions, m_pVRoots[i].AuthLevel));
return &(m_pVRoots[i]);
}
// It's possible for a virtual root name to have multiple slashes, i.e.
// '/a/b' could map to '\windows\www' whereas '/a' could be something else.
// We need to accomodate this case, and also the case where a file name begins
// with the same sequence of characters as a virtual root name -> i.e.
// a request for '/webAdmin.htm' should not map to vroot '/webAdmin/', but instead to '/'.
// First, figure out how much of URL to compare to a vroot based on number of slashes in vroot.
int iNumSlashesInVRoot = m_pVRoots[i].iNumSlashes;
// There's not enough slashes to possibly match, i.e. a request for /ABCD on vroot[i] = /A/B can't work.
if (iInputSlashes < iNumSlashesInVRoot)
continue;
// Skip to either end of string or first '/'. Go iNumSlashesInVRoot after
// the first '/' if there is one, and then stop looking ahead. This is len of URL to check against.
while (iNumSlashesInVRoot) {
PCSTR szFirstUrlSlashSave = szFirstUrlSlash;
szFirstUrlSlash = GetNextSlash(szFirstUrlSlash+1);
DEBUGCHK(szFirstUrlSlash || (iNumSlashesInVRoot == 1));
if (NULL == szFirstUrlSlash)
szFirstUrlSlash = strchr(szFirstUrlSlashSave,'\0');
iNumSlashesInVRoot--;
}
int iURLLen = szFirstUrlSlash-pszInputURL;
DEBUGCHK(iURLLen <= iInputLen);
if ((iURLLen == m_pVRoots[i].iURLLen) && (0 == _memicmp(pszInputURL, m_pVRoots[i].pszURL, iURLLen))) {
/*
if (m_pVRoots[i].fRootDir) {
// If it's not root dir, always matched. Otherwise it's possible
// there wasn't a match. For root dirs, pszURL[iLen] is always "/"
if (! (m_pVRoots[i].iURLLen == 1 || pszInputURL[iLen] == '/' || pszInputURL[iLen] == '\0'))
continue;
}
*/
DEBUGMSG(ZONE_VROOTS, (L"HTTPD: URL %a matched VRoot %a (path %s, perm=%d, auth=%d)\r\n",
pszInputURL, m_pVRoots[i].pszURL, m_pVRoots[i].wszPath, m_pVRoots[i].dwPermissions, m_pVRoots[i].AuthLevel));
return &(m_pVRoots[i]);
}
}
DEBUGMSG(ZONE_VROOTS, (L"HTTPD: URL %a did not matched any VRoot\r\n", pszInputURL));
return NULL;
}
BOOL Init(CReg *pWebsite, BOOL fDefaultDirBrowse, BOOL fDefaultBasic, BOOL fDefaultNTLM, BOOL fDefaultNegotiate) {
const WCHAR cszDLL[] = L".dll";
const WCHAR cszASP[] = L".asp";
int err = 0; // err variable is used in non-Debug mode
BOOL fChange;
int i=0;
// Registry doesn't allow keynames longer than MAX_PATH so we won't map URL prefixes longer than MAX_PATH
WCHAR wszURL[MAX_PATH+1];
WCHAR wszPath[MAX_PATH+1];
wszURL[0]=wszPath[0]=0;
// open the VRoots key
CReg topreg((HKEY) (*pWebsite), RK_HTTPDVROOTS);
// allocate space for as many VRoots as we have subkeys
m_nVRoots = topreg.NumSubkeys();
if(!m_nVRoots)
myleave(80);
// Zero the memory so we know what to deallocate and what not to.
if(!(m_pVRoots = MyRgAllocZ(VROOTINFO, m_nVRoots)))
myleave(81);
// enumerate all subkeys. Their names are URLs, their default value is the corresponding path
// Note: EnumKey takes sizes in chars, not bytes!
for(i = 0; topreg.EnumKey(wszURL, CCHSIZEOF(wszURL)); ) {
CReg subreg(topreg, wszURL);
DEBUGCHK(i < m_nVRoots);
memset(&m_pVRoots[i],0,sizeof(VROOTINFO));
// get the unnamed value. Again size is in chars, not bytes.
if(!subreg.ValueSZ(NULL, wszPath, CCHSIZEOF(wszPath))) {
// iURLLen and iPathLen set to 0 already, so no case of corruption in MatchVRoot
subreg.Reset();
continue;
}
else {
CHAR pszURL[MAX_PATH+1];
// convert URL to MBCS
int iLen = m_pVRoots[i].iURLLen = MyW2A(wszURL, pszURL, sizeof(pszURL));
if(!iLen)
{ myleave(83); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -