Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

989 lines
21 KiB

#include "pch.h"
#include "store.hpp"
#define CF_COMPRESSED 0x1
#define TLS // __declspec( thread )
#if defined(_WIN64) && defined(_M_IA64)
#pragma section(".base", long, read, write)
extern "C"
__declspec(allocate(".base"))
extern
IMAGE_DOS_HEADER __ImageBase;
#else
extern "C"
extern
IMAGE_DOS_HEADER __ImageBase;
#endif
HINSTANCE ghSymSrv = (HINSTANCE)&__ImageBase;
UINT_PTR goptions = SSRVOPT_DWORD;
DWORD gptype = SSRVOPT_DWORD;
PSYMBOLSERVERCALLBACKPROC gcallback = NULL;
ULONG64 gcontext = 0;
HWND ghwndParent = (HWND)0;
char gproxy[MAX_PATH + 1] = "";
int gdbgout = -1;
char gdstore[MAX_PATH + 1] = "";
void
PrepOutputString(
char *in,
char *out,
int len
)
{
int i;
*out = 0;
for (i = 0; *in && i < len; i++, in++, out++) {
if (*in == '\b')
break;
*out = *in;
}
*out = 0;
}
VOID
OutputDbgString(
char *sz
)
{
char sztxt[3000];
PrepOutputString(sz, sztxt, 3000);
if (*sztxt)
OutputDebugString(sztxt);
}
__inline
BOOL
DoCallback(
DWORD action,
ULONG64 data
)
{
return gcallback(action, data, gcontext);
}
BOOL
PostEvent(
PIMAGEHLP_CBA_EVENT evt
)
{
BOOL fdbgout = false;
if (!*evt->desc)
return true;
// write to debug terminal, if called for
if (gdbgout == 1) {
fdbgout = true;
OutputDbgString(evt->desc);
}
// don't pass info-level messages, unless told to
if ((evt->severity <= sevInfo) && !(goptions & SSRVOPT_TRACE))
return true;
// If there is no callback function, send to the debug terminal.
if (!gcallback) {
if (!fdbgout)
OutputDbgString(evt->desc);
return true;
}
// Otherwise call the callback function.
return DoCallback(SSRVACTION_EVENT, (ULONG64)evt);
}
BOOL
WINAPIV
evtprint(
DWORD severity,
DWORD code,
PVOID object,
LPSTR format,
...
)
{
static char buf[1000] = "";
IMAGEHLP_CBA_EVENT evt;
va_list args;
va_start(args, format);
wvsprintf(buf, format, args);
va_end(args);
if (!*buf)
return true;
evt.severity = severity;
evt.code = code;
evt.desc = buf;
evt.object = object;
return PostEvent(&evt);
}
int
_eprint(
LPSTR format,
...
)
{
static char buf[1000] = "";
va_list args;
if (!format || !*format)
return 1;
if (!(goptions & SSRVOPT_TRACE) && gdbgout != 1)
return 1;
va_start(args, format);
wvsprintf(buf, format, args);
va_end(args);
if (!evtprint(sevInfo, 0, NULL, buf))
if (gcallback)
gcallback(SSRVACTION_TRACE, (ULONG64)buf, gcontext);
return 1;
}
DBGEPRINT geprint = _eprint;
int
_dprint(
LPSTR format,
...
)
{
static char buf[1000] = "SYMSRV: ";
va_list args;
if (!format || !*format)
return 1;
if (!(goptions & SSRVOPT_TRACE) && gdbgout != 1)
return 1;
va_start(args, format);
wvsprintf(buf + 9, format, args);
va_end(args);
return _eprint(buf);
}
DBGPRINT gdprint = NULL; // _dprint;
// this one is for calling from dload.cpp
int
__dprint(
LPSTR sz
)
{
static char buf[1000] = "SYMSRV: ";
va_list args;
if (!sz || !*sz)
return 1;
CopyStrArray(buf, "SYMSRV: ");
CatStrArray(buf, sz);
if (gcallback)
gcallback(SSRVACTION_TRACE, (ULONG64)buf, gcontext);
if (!gcallback || (gdbgout == 1))
OutputDbgString(buf);
return 1;
}
int
_querycancel(
)
{
BOOL rc;
BOOL cancel = false;
if (!gcallback)
return false;
rc = gcallback(SSRVACTION_QUERYCANCEL, (ULONG64)&cancel, gcontext);
if (rc && cancel)
return true;
return false;
}
QUERYCANCEL gquerycancel = _querycancel;
BOOL
SetError(
DWORD err
)
{
SetLastError(err);
return 0;
}
BOOL
copy(
IN PCSTR trgsite,
IN PCSTR srcsite,
IN PCSTR rpath,
IN PCSTR file,
OUT PSTR trg, // must be at least MAX_PATH elements
IN DWORD flags
)
{
BOOL rc;
DWORD type = stUNC;
CHAR epath[MAX_PATH + 1];
CHAR srcbuf[MAX_PATH + 1];
CHAR tsite[MAX_PATH + 1];
CHAR ssite[MAX_PATH + 1];
PSTR src;
Store *store;
DWORD ec;
assert(trgsite && srcsite);
// use the default downstream store, if specified
CopyStrArray(tsite, (*trgsite) ? trgsite : gdstore);
CopyStrArray(ssite, srcsite);
// get the store type of the target store
type = GetStoreType(tsite);
switch (type) {
case stUNC:
break;
case stHTTP:
case stHTTPS:
// Can't use http for the target.
// If a source is specifed, then bail.
if (*ssite)
return SetError(ERROR_INVALID_PARAMETER);
// Otherwise, just use the default downstream store for a target.
CopyStrArray(ssite, tsite);
CopyStrArray(tsite, gdstore);
break;
case stError:
return SetError(ERROR_INVALID_PARAMETER);
default:
return SetError(ERROR_INVALID_NAME); }
// MAYBE PUT A CHECK IN HERE FOR A CAB. LIKE IF THE DIRECTORY IS
// ACTUALLY A COMPRESSED FILE AND RETURN stCAB.
// generate full target path
pathcpy(trg, tsite, rpath, MAX_PATH);
pathcat(trg, file, MAX_PATH);
// if file exists, return it
ec = FileStatus(trg);
if (!ec) {
return true;
} else if (ec == ERROR_NOT_READY) {
dprint("%s - drive not ready\n", trg);
return false;
}
if (ReadFilePtr(trg, MAX_PATH)) {
ec = FileStatus(trg);
if (ec == NO_ERROR)
return true;
dprint("%s - %s\n", trg, FormatStatus(ec));
return false;
}
if (!*ssite) {
ec = FileStatus(CompressedFileName(trg));
if (ec != NO_ERROR) {
// if there is no source to copy from, then error
dprint("%s - file not found\n", trg);
return SetError(ERROR_FILE_NOT_FOUND);
}
// There is a compressed file..
// Expand it to the default store.
CopyStrArray(ssite, tsite);
CopyStrArray(tsite, gdstore);
pathcpy(trg, tsite, rpath, MAX_PATH);
pathcat(trg, file, MAX_PATH);
ec = FileStatus(trg);
if (ec == NO_ERROR)
return true;
}
if (goptions & SSRVOPT_SECURE) {
dprint("%s - file copy not allowed in secure mode\n", trg);
return SetError(ERROR_ACCESS_DENIED);
}
if (!EnsurePathExists(trg, epath, DIMA(epath))) {
dprint("%s - couldn't create target path\n", trg);
return SetError(ERROR_PATH_NOT_FOUND);
}
store = GetStore(ssite);
if (!store)
return false;
rc = store->init();
if (!rc)
return false;
rc = store->copy(rpath, file, tsite);
// test the results and set the return value
if (rc && !FileStatus(trg))
return true;
UndoPath(trg, epath);
return false;
}
BOOL
ping(
IN PCSTR trgsite,
IN PCSTR srcsite,
IN PCSTR rpath,
IN PCSTR file,
OUT PSTR trg,
IN DWORD flags
)
{
BOOL rc;
DWORD type = stUNC;
CHAR epath[_MAX_PATH];
CHAR srcbuf[_MAX_PATH];
PSTR src;
Store *store;
DWORD ec;
store = GetStore(srcsite);
if (!store)
return false;
rc = store->init();
if (!rc)
return false;
rc = store->ping();
return rc;
}
void
CatStrDWORD(
IN OUT PSTR sz,
IN DWORD value,
IN DWORD size
)
{
CHAR buf[MAX_PATH + 256];
assert(sz);
if (!value)
return;
wsprintf(buf, "%s%x", sz, value); // SECURITY: This will take a 256 digit DWORD.
CopyString(sz, buf, size);
}
void
CatStrGUID(
IN OUT PSTR sz,
IN GUID *guid,
IN DWORD size
)
{
CHAR buf[MAX_PATH + 256];
BYTE byte;
int i;
assert(sz);
if (!guid)
return;
// append the first DWORD in the pointer
wsprintf(buf, "%08X", guid->Data1);
CatString(sz, buf, size);
// this will catch the passing of a PDWORD and avoid
// all the GUID parsing
if (!guid->Data2 && !guid->Data3) {
for (i = 0, byte = 0; i < 8; i++) {
byte |= guid->Data4[i];
if (byte)
break;
}
if (!byte)
return;
}
// go ahead and add the rest of the GUID
wsprintf(buf, "%04X", guid->Data2);
CatString(sz, buf, size);
wsprintf(buf, "%04X", guid->Data3);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[0]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[1]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[2]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[3]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[4]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[5]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[6]);
CatString(sz, buf, size);
wsprintf(buf, "%02X", guid->Data4[7]);
CatString(sz, buf, size);
}
void
CatStrOldGUID(
IN OUT PSTR sz,
IN GUID *guid,
IN DWORD size
)
{
CHAR buf[MAX_PATH + 256];
BYTE byte;
int i;
assert(sz);
if (!guid)
return;
// append the first DWORD in the pointer
wsprintf(buf, "%8x", guid->Data1);
CatString(sz, buf, size);
// this will catch the passing of a PDWORD and avoid
// all the GUID parsing
if (!guid->Data2 && !guid->Data3) {
for (i = 0, byte = 0; i < 8; i++) {
byte |= guid->Data4[i];
if (byte)
break;
}
if (!byte)
return;
}
// go ahead and add the rest of the GUID
wsprintf(buf, "%4x", guid->Data2);
CatString(sz, buf, size);
wsprintf(buf, "%4x", guid->Data3);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[0]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[1]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[2]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[3]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[4]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[5]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[6]);
CatString(sz, buf, size);
wsprintf(buf, "%2x", guid->Data4[7]);
CatString(sz, buf, size);
}
void
CatStrID(
IN OUT PSTR sz,
PVOID id,
DWORD paramtype,
DWORD size
)
{
switch (paramtype)
{
case SSRVOPT_DWORD:
CatStrDWORD(sz, PtrToUlong(id), size);
break;
case SSRVOPT_DWORDPTR:
CatStrDWORD(sz, *(DWORD *)id, size);
break;
case SSRVOPT_GUIDPTR:
CatStrGUID(sz, (GUID *)id, size);
break;
case SSRVOPT_OLDGUIDPTR:
CatStrOldGUID(sz, (GUID *)id, size);
break;
default:
break;
}
}
// for Barb and Greg only. I'm going to get rid of these...
void
AppendHexStringWithDWORD(
IN OUT PSTR sz,
IN DWORD value
)
{
return CatStrDWORD(sz, value, MAX_PATH);
}
void
AppendHexStringWithGUID(
IN OUT PSTR sz,
IN GUID *guid
)
{
return CatStrGUID(sz, guid, MAX_PATH);
}
void
AppendHexStringWithOldGUID(
IN OUT PSTR sz,
IN GUID *guid
)
{
return CatStrOldGUID(sz, guid, MAX_PATH);
}
void
AppendHexStringWithID(
IN OUT PSTR sz,
PVOID id,
DWORD paramtype
)
{
return CatStrID(sz, id, paramtype, MAX_PATH);
}
/*
* Given a string, find the next '*' and zero it
* out to convert the current token into it's
* own string. Return the address of the next character,
* if there are any more strings to parse.
*/
PSTR
ExtractToken(
PSTR in,
PSTR out,
size_t size
)
{
PSTR p = in;
*out = 0;
if (!in || !*in)
return NULL;
for (;*p; p++) {
if (*p == '*') {
*p = 0;
p++;
break;
}
}
CopyString(out, in, size);
return (*p) ? p : NULL;
}
BOOL
BuildRelativePath(
OUT LPSTR rpath,
IN LPCSTR filename,
IN PVOID id, // first number in directory name
IN DWORD val2, // second number in directory name
IN DWORD val3, // third number in directory name
IN DWORD size
)
{
LPSTR p;
assert(rpath);
CopyString(rpath, filename, size);
EnsureTrailingBackslash(rpath);
CatStrID(rpath, id, gptype, size);
CatStrDWORD(rpath, val2, size);
CatStrDWORD(rpath, val3, size);
for (p = rpath + strlen(rpath) - 1; p > rpath; p--) {
if (*p == '\\') {
dprint("Insufficient information querying for %s\n", filename);
SetLastError(ERROR_MORE_DATA);
return false;
}
if (*p != '0')
return true;
}
return true;
}
BOOL
SymbolServerClose()
{
return true;
}
BOOL
TestParameters(
IN PCSTR params, // server and cache path
IN PCSTR filename, // name of file to search for
IN PVOID id, // first number in directory name
IN DWORD val2, // second number in directory name
IN DWORD val3, // third number in directory name
OUT PSTR path // return validated file path here
)
{
__try {
if (path)
*path = 0;
} __except(EXCEPTION_EXECUTE_HANDLER) {
return SetError(ERROR_INVALID_PARAMETER);
}
if (!path || !params || !*params || !filename || !*filename || (!id && !val2 && !val3))
return SetError(ERROR_INVALID_PARAMETER);
if (strlen(filename) > 100) {
dprint("%s - filename cannot exceed 100 characters\n", filename);
return SetError(ERROR_INVALID_PARAMETER);
}
switch (gptype)
{
case SSRVOPT_GUIDPTR:
case SSRVOPT_OLDGUIDPTR:
// this test should AV if a valid GUID pointer wasn't passed in
__try {
GUID *guid = (GUID *)id;
BYTE b;
b = guid->Data4[8];
} __except(EXCEPTION_EXECUTE_HANDLER) {
return SetError(ERROR_INVALID_PARAMETER);
}
break;
case SSRVOPT_DWORDPTR:
// this test should AV if a valid DWORD pointer wasn't passed in
__try {
DWORD dword = *(DWORD *)id;
} __except(EXCEPTION_EXECUTE_HANDLER) {
return SetError(ERROR_INVALID_PARAMETER);
}
break;
}
return true;
}
BOOL
SymbolServer(
IN PCSTR params, // server and cache path
IN PCSTR filename, // name of file to search for
IN PVOID id, // first number in directory name
IN DWORD val2, // second number in directory name
IN DWORD val3, // third number in directory name
OUT PSTR path // return validated file path here
)
{
CHAR *p;
CHAR tdir[MAX_PATH + 1] = "";
CHAR sdir[MAX_PATH + 1] = "";
CHAR sz[MAX_PATH * 2 + 3];
CHAR rpath[MAX_PATH + 1];
BOOL rc;
if (!TestParameters(params, filename, id, val2, val3, path))
return false;
// test environment
if (gdbgout == -1) {
if (GetEnvironmentVariable("SYMSRV_DBGOUT", sz, MAX_PATH))
gdbgout = 1;
else
gdbgout = 0;
*sz = 0;
}
// parse parameters
CopyStrArray(sz, params);
p = ExtractToken(sz, tdir, DIMA(tdir)); // 1st path is where the symbol should be
p = ExtractToken(p, sdir, DIMA(sdir)); // 2nd optional path is the server to copy from
// build the relative path to the target symbol file
if (!BuildRelativePath(rpath, filename, id, val2, val3, DIMA(rpath)))
return false;
// if no_copy option is set, just return the path to the target
if (goptions & SSRVOPT_NOCOPY) {
pathcpy(path, tdir, rpath, MAX_PATH);
pathcat(path, filename, MAX_PATH);
return true;
}
// copy from server to specified symbol path
rc = copy(tdir, sdir, rpath, filename, path, 0);
if (!rc)
*path = 0;
return rc;
}
BOOL
SymbolServerSetOptions(
UINT_PTR options,
ULONG64 data
)
{
DWORD ptype;
// set the callback function
if (options & SSRVOPT_CALLBACK) {
if (data) {
goptions |= SSRVOPT_CALLBACK;
gcallback = (PSYMBOLSERVERCALLBACKPROC)data;
} else {
goptions &= ~SSRVOPT_CALLBACK;
gcallback = NULL;
}
}
// set the callback context
if (options & SSRVOPT_SETCONTEXT)
gcontext = data;
// when this flags is set, trace output will be delivered
if (options & SSRVOPT_TRACE) {
if (data) {
goptions |= SSRVOPT_TRACE;
setdprint(_dprint);
} else {
goptions &= ~SSRVOPT_TRACE;
setdprint(NULL);
}
}
// set the parameter type for the first ID parameter
if (options & SSRVOPT_PARAMTYPE) {
switch(data) {
case SSRVOPT_DWORD:
case SSRVOPT_DWORDPTR:
case SSRVOPT_GUIDPTR:
case SSRVOPT_OLDGUIDPTR:
goptions &= ~(SSRVOPT_DWORD | SSRVOPT_DWORDPTR | SSRVOPT_GUIDPTR | SSRVOPT_OLDGUIDPTR);
goptions |= data;
gptype = (DWORD)data;
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
}
// set the parameter type for the first ID paramter - OLD SYNTAX
// the if statements provide and order of precedence
ptype = 0;
if (options & SSRVOPT_DWORD)
ptype = SSRVOPT_DWORD;
if (options & SSRVOPT_DWORDPTR)
ptype = SSRVOPT_DWORDPTR;
if (options & SSRVOPT_GUIDPTR)
ptype = SSRVOPT_GUIDPTR;
if (options & SSRVOPT_OLDGUIDPTR)
ptype = SSRVOPT_OLDGUIDPTR;
if (ptype) {
goptions &= ~(SSRVOPT_DWORD | SSRVOPT_DWORDPTR | SSRVOPT_GUIDPTR | SSRVOPT_OLDGUIDPTR);
if (data) {
goptions |= ptype;
gptype = ptype;
} else if (gptype == ptype) {
// when turning off a type, reset it to DWORD
goptions |= SSRVOPT_DWORD;
gptype = SSRVOPT_DWORD;
}
}
// if this flag is set, no GUI will be displayed
if (options & SSRVOPT_UNATTENDED) {
if (data)
goptions |= SSRVOPT_UNATTENDED;
else
goptions &= ~SSRVOPT_UNATTENDED;
}
// when this is set, the existence of the returned file path is not checked
if (options & SSRVOPT_NOCOPY) {
if (data)
goptions |= SSRVOPT_NOCOPY;
else
goptions &= ~SSRVOPT_NOCOPY;
}
// this window handle is used as a parent for dialog boxes
if (options & SSRVOPT_PARENTWIN) {
SetParentWindow((HWND)data);
if (data)
goptions |= SSRVOPT_PARENTWIN;
else
goptions &= ~SSRVOPT_PARENTWIN;
}
// when running in secure mode, we don't copy files to downstream stores
if (options & SSRVOPT_SECURE) {
if (data)
goptions |= SSRVOPT_SECURE;
else
goptions &= ~SSRVOPT_SECURE;
}
// set http proxy
if (options & SSRVOPT_PROXY) {
if (data) {
goptions |= SSRVOPT_PROXY;
CopyStrArray(gproxy, (char *)data);
setproxy(gproxy);
} else {
goptions &= ~SSRVOPT_PROXY;
*gproxy = 0;
setproxy(NULL);
}
}
// set default downstream store
if (options & SSRVOPT_DOWNSTREAM_STORE) {
if (data) {
goptions |= SSRVOPT_DOWNSTREAM_STORE;
CopyStrArray(gdstore, (char *)data);
setdstore(gdstore);
} else {
goptions &= ~SSRVOPT_DOWNSTREAM_STORE;
*gdstore = 0;
setdstore(NULL);
}
}
SetStoreOptions(goptions);
return true;
}
UINT_PTR
SymbolServerGetOptions(
)
{
return goptions;
}
BOOL
SymbolServerPing(
IN PCSTR params // server and cache path
)
{
CHAR *p;
CHAR sz[MAX_PATH * 2 + 3];
CHAR tdir[MAX_PATH + 1] = "";
CHAR sdir[MAX_PATH + 1] = "";
CHAR rpath[MAX_PATH + 1];
CHAR filename[MAX_PATH + 1];
CHAR path[MAX_PATH + 1];
if (!params || !*params)
return SetError(ERROR_INVALID_PARAMETER);
// parse parameters
// parse parameters
CopyStrArray(sz, params);
p = ExtractToken(sz, tdir, DIMA(tdir)); // 1st path is where the symbol should be
p = ExtractToken(p, sdir, DIMA(sdir)); // 2nd optional path is the server to copy from
// copy from server to specified symbol path
return ping(tdir, sdir, rpath, filename, path, 0);
return true;
}