📄 filesvr.cxx
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// Known problems:
// 1. Encodes XML stream into multibytes, not UTF-8
//
#include <windows.h>
#include <obexparser.h>
#include <obexserver.h>
#include <stdio.h>
#include <tchar.h>
#include <winsock.h>
#include <svslog.hxx>
#include "MD5.h"
#define OBEX_FTP_DEBUG_REG L"Software\\Microsoft\\Obex"
#define OBEX_FTP_BASE_REG OBEX_KEY_SERVERS L"\\{F9ec7bc4-953c-11d2-984e-525400dc9e09}"
#define OBEX_FTP_BASE_DIR L"\\temp\\ftp"
#define DEBUG_FTP_TRACE 0x00000002
#define OBEX_FTP_MAXPACKET 32 * 1024
#define OBEX_BIGBUFFER 1024
#define OBEX_SMALLBUFFER 128
#define OBEX_TIMEOUT_AUTHENTICATIONS_AFTER_N_MILLISEC 5000
#define CRLF L"\r\n"
enum CURRENT_OP {
NONE,
SEND,
RECEIVE,
FILELIST
};
class AuthList
{
public:
BYTE challenge[16];
BYTE nonce[18]; //target+size+nonce
AuthList *pNext;
DWORD startTime;
};
class FileXFer {
public:
FileXFer *pNext;
WCHAR szCurDir[_MAX_PATH];
WCHAR szBaseDir[_MAX_PATH];
WCHAR szCurFile[_MAX_PATH];
BYTE nonce[18];
BOOL fIsAuthenticated;
BOOL fNonceSet;
BOOL fNameHeaderFound;
BOOL fDir;
unsigned int uiConnectionId;
unsigned int uiPacketLimit;
CURRENT_OP op;
HANDLE hFile;
unsigned char *ucListing;
int cListingSize;
int cCompleted;
};
class MemStream {
unsigned char *ucBuffer;
int cAllocated;
int cFilled;
MemAlloc alloc;
MemFree free;
public:
MemStream (MemAlloc ma, MemFree mf) {
memset (this, 0, sizeof(*this));
alloc = ma;
free = mf;
}
int Length (void) {
return cFilled > 0 ? cFilled - 1 : 0;
}
unsigned char *Buffer (void) {
return ucBuffer;
}
int wSTREAMprintf (WCHAR *lpszFormat, ...) {
if(!alloc || !free)
return FALSE;
va_list args;
va_start (args, lpszFormat);
WCHAR szBigBuffer[OBEX_BIGBUFFER];
wvsprintf (szBigBuffer, lpszFormat, args);
va_end (args);
int cNewNeeded = WideCharToMultiByte (CP_ACP, 0, szBigBuffer, -1, NULL, 0, NULL, NULL);
if (cNewNeeded <= 0)
return FALSE;
if (cAllocated < cFilled + cNewNeeded - 1) {
unsigned char *sz = (unsigned char *)alloc (cFilled + cNewNeeded - 1 + OBEX_SMALLBUFFER);
if (! sz)
return FALSE;
cAllocated = cFilled + cNewNeeded - 1 + OBEX_SMALLBUFFER;
if (ucBuffer)
{
memcpy (sz, ucBuffer, cFilled);
free(ucBuffer);
}
ucBuffer = sz;
}
if (cFilled > 0)
cFilled -= 1; // account for extra 0
WideCharToMultiByte (CP_ACP, 0, szBigBuffer, -1, (char *)&ucBuffer[cFilled], cNewNeeded, NULL, NULL);
cFilled += cNewNeeded;
return cFilled;
}
};
//functions
static int HandlePacketAuthentication(ObexTransaction *pOT, FileXFer *pConn);
//globals
static HMODULE g_hMod;
static CRITICAL_SECTION g_cs;
static FileXFer *g_pConn = NULL;
static AuthList *g_pAuthList = NULL;
//////////////////////////////////////////////////////////////////////
// Utility section
//////////////////////////////////////////////////////////////////////
static HRESULT MakeResponse (const WCHAR *_pszPassToUse, BYTE *bChallenge, BYTE *bResponse) {
INT cp = CP_UTF8;
UCHAR ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
if (! ucPassLen)
{
cp = CP_ACP;
ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
}
if (! ucPassLen)
return E_FAIL;
UINT uiEncodeSize = 16 + 1 + ucPassLen;
BYTE bEncodeBuffer[512];
BYTE *bToEncode = (uiEncodeSize > sizeof(bEncodeBuffer)) ? new BYTE[uiEncodeSize] : bEncodeBuffer;
if (! bToEncode)
return E_FAIL;
memcpy (bToEncode, bChallenge, 16);
bToEncode[16] = ':';
HRESULT hr = E_FAIL;
if (WideCharToMultiByte (cp, 0, _pszPassToUse, -1, (char *)(bToEncode + 17), ucPassLen, NULL, NULL))
{
MD5(bResponse, bToEncode, uiEncodeSize - 1); // -1 because we don't want terminating '\0'
hr = ERROR_SUCCESS;
}
if (bToEncode != bEncodeBuffer)
delete [] bToEncode;
return ERROR_SUCCESS;
}
static HRESULT MakeNonce (const WCHAR *_pszPassToUse, BYTE *bMyNonce)
{
SYSTEMTIME st;
GetSystemTime(&st);
INT cp = CP_UTF8;
UCHAR ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
if (! ucPassLen)
{
cp = CP_ACP;
ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
}
if (! ucPassLen)
return E_FAIL;
UINT uiEncodeSize = 16 + 1 + ucPassLen;
BYTE bEncodeBuffer[512];
BYTE *bToEncode = (uiEncodeSize > sizeof(bEncodeBuffer)) ? new BYTE[uiEncodeSize] : bEncodeBuffer;
if (! bToEncode)
return E_FAIL;
//16 bytes plus NULL ... so its okay to directly write in bToEncode... the NULL will be replaced!
sprintf((char *)bToEncode, "%4.4d%2.2d%2.2dT%2.2d%2.2d%2.2dZ", st.wYear,st.wMonth,st.wDay, st.wHour,st.wMinute,st.wSecond);
SVSUTIL_ASSERT(16 == strlen((char *)bToEncode));
bToEncode[16] = ':';
HRESULT hr = E_FAIL;
if (WideCharToMultiByte (cp, 0, _pszPassToUse, -1, (char *)(bToEncode + 17), ucPassLen, NULL, NULL))
{
MD5(bMyNonce, bToEncode, uiEncodeSize - 1); // -1 because we don't want terminating '\0'
hr = ERROR_SUCCESS;
}
if (bToEncode != bEncodeBuffer)
delete [] bToEncode;
return hr;
}
static int CheckNameForValidity (WCHAR *szName) {
if (wcscmp (szName, L"..") == 0)
return FALSE;
if (wcscmp (szName, L".") == 0)
return FALSE;
while (*szName != '\0') {
if (*szName == '\\')
return FALSE;
if (*szName == '/')
return FALSE;
++szName;
}
return TRUE;
}
static void GetTimeString (WCHAR *szBuf, FILETIME ft) {
SYSTEMTIME st;
FileTimeToSystemTime (&ft, &st);
wsprintf (szBuf, L"%04d%02d%02dT%02d%02d%02dZ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
}
static int GetDirListing (FileXFer *pConn, ObexTransaction *pOT) {
IFDBG(svslog_DebugOut (DEBUG_FTP_TRACE, L"[OBEX-FTP] Getting dir listing for %s\n", pConn->szCurFile));
//if alloc/free functions are null return
if(!pOT->ObexAlloc || !pOT->ObexFree)
return FALSE;
//if its the root directory, dont put in the \\'s
UINT strLen = wcslen(pConn->szCurFile);
if(strLen && ('\\' == pConn->szCurFile[strLen-1]))
pConn->szCurFile[strLen-1] = 0;
DWORD dwAttr = GetFileAttributes (pConn->szCurFile);
if ((dwAttr == 0xffffffff) || ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) == 0))
return FALSE;
wcscat (pConn->szCurFile, L"\\*.*");
MemStream stm (pOT->ObexAlloc, pOT->ObexFree);
if(!stm.wSTREAMprintf (L"<?xml version=\"1.0\"?>" CRLF))
return FALSE;
if(!stm.wSTREAMprintf (L"<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">" CRLF))
return FALSE;
if(!stm.wSTREAMprintf (L"<folder-listing version=\"1.0\">" CRLF))
return FALSE;
WCHAR *pPath = wcsrchr(pConn->szCurDir, L'\\');
stm.wSTREAMprintf (L" <parent-folder name=\"%s\" />" CRLF, (pPath) ? (pPath+1) : pConn->szCurDir);
WIN32_FIND_DATA wfd;
HANDLE hSearch = FindFirstFile (pConn->szCurFile, &wfd);
if (hSearch != INVALID_HANDLE_VALUE) {
do {
WCHAR szDateBuf[30];
GetTimeString (szDateBuf, wfd.ftCreationTime);
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
stm.wSTREAMprintf (L" <folder name=\"%s\" created=\"%s\"/>" CRLF, wfd.cFileName, szDateBuf);
else
stm.wSTREAMprintf (L" <file name=\"%s\" created=\"%s\" size=\"%d\"/>" CRLF, wfd.cFileName, szDateBuf, wfd.nFileSizeLow);
} while (FindNextFile (hSearch, &wfd));
FindClose(hSearch);
}
stm.wSTREAMprintf (L"</folder-listing>" CRLF);
pConn->op = FILELIST;
pConn->cListingSize = stm.Length ();
pConn->cCompleted = 0;
pConn->ucListing = stm.Buffer ();
return TRUE;
}
static void CloseConnection (ObexTransaction *pOT, FileXFer *pConn) {
IFDBG(svslog_DebugOut (DEBUG_FTP_TRACE, L"[OBEX-FTP] Closing the connection 0x%08x\n", pConn->uiConnectionId));
if ((pConn->op == SEND) || (pConn->op == RECEIVE)) {
if (pConn->hFile != INVALID_HANDLE_VALUE)
CloseHandle (pConn->hFile);
} else if (pConn->op == FILELIST) {
if (pConn->ucListing)
pOT->ObexFree (pConn->ucListing);
}
pOT->ObexFree (pConn);
}
DWORD CanWrite()
{
HKEY hk;
DWORD fCanWrite = FALSE;
//
// Fetch the read only bit from the registry
if (ERROR_SUCCESS == RegOpenKeyEx (HKEY_LOCAL_MACHINE, OBEX_FTP_BASE_REG, 0, KEY_READ, &hk))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -