mirror of https://github.com/lianthony/NT4.0
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.
9685 lines
288 KiB
9685 lines
288 KiB
//--------------------------------------------------------------
|
|
//
|
|
// File: perfcli.cxx
|
|
//
|
|
// Contents: First attempt at getting perfcliing to work
|
|
//
|
|
// This is the client side
|
|
//
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <io.h>
|
|
#include <malloc.h>
|
|
|
|
#include <ole2.h>
|
|
#include "..\idl\itest.h"
|
|
#include <objerror.h>
|
|
#include <dog.h>
|
|
#include <winnt.h> // Security definitions
|
|
|
|
/***************************************************************************/
|
|
/* Macros. */
|
|
#define ASSERT( result, message ) \
|
|
if ((result) != 0) \
|
|
{ \
|
|
printf( "%s: 0x%x\n", (message), result ); \
|
|
goto cleanup; \
|
|
}
|
|
|
|
#define ASSERT_EXPR( expr, message ) \
|
|
if (!(expr)) \
|
|
{ \
|
|
printf( "%s\n", (message) ); \
|
|
goto cleanup; \
|
|
}
|
|
|
|
#define ASSERT_THREAD() \
|
|
if ((ThreadMode == COINIT_SINGLETHREADED || \
|
|
ThreadMode == COINIT_APARTMENTTHREADED) && \
|
|
(my_id.process != GetCurrentProcessId() || \
|
|
my_id.thread != GetCurrentThreadId())) \
|
|
return RPC_E_WRONG_THREAD;
|
|
|
|
|
|
#define MAKE_WIN32( status ) \
|
|
MAKE_SCODE( SEVERITY_ERROR, FACILITY_WIN32, (status) )
|
|
|
|
#define MCoCopyProxy (*GCoCopyProxy)
|
|
#define MCoGetCallContext (*GCoGetCallContext)
|
|
#define MCoImpersonateClient (*GCoImpersonateClient)
|
|
#define MCoInitializeSecurity (*GCoInitializeSecurity)
|
|
#define MCoQueryAuthenticationServices (*GCoQueryAuthenticationServices)
|
|
#define MCoQueryClientBlanket (*GCoQueryClientBlanket)
|
|
#define MCoQueryProxyBlanket (*GCoQueryProxyBlanket)
|
|
#define MCoRevertToSelf (*GCoRevertToSelf)
|
|
#define MCoSetProxyBlanket (*GCoSetProxyBlanket)
|
|
#define MCoSwitchCallContext (*GCoSwitchCallContext)
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Definitions. */
|
|
|
|
#define MAX_CALLS 1000
|
|
#define MAX_THREADS 10
|
|
#define NUM_MARSHAL_LOOP 10
|
|
#define REGISTRY_ENTRY_LEN 256
|
|
#define STATUS_DELAY 2000
|
|
|
|
const int MAX_NAME = 80;
|
|
const int NUM_CLASS_IDS = 10;
|
|
const int NUM_INTERFACE_IDS = 7;
|
|
|
|
const char REG_INTERFACE_CLASS[] = "{60000200-76d7-11cf-9af1-0020af6e72f4}";
|
|
const char REG_PROXY_NAME[] = "ITest proxy";
|
|
const char REG_PROXY_DLL[] = "app.exe";
|
|
const char REG_APPID_NAME[] = "Application";
|
|
const char REG_APP_EXE[] = "app.exe";
|
|
const char REG_LOGGED_ON[] = "Interactive User";
|
|
const char REG_CLASS_ID[] = "CLSID\\{60000000-AB0F-101A-B4AE-08002B30612C}";
|
|
const char REG_CLASS_EXE[] = "CLSID\\{60000000-AB0F-101A-B4AE-08002B30612C}\\LocalServer32";
|
|
const char *REG_INTERFACE_NAME[NUM_INTERFACE_IDS] =
|
|
{
|
|
"ITest",
|
|
"ITestNoneImp",
|
|
"ITestConnectImp",
|
|
"ITestEncryptImp",
|
|
"ITestNoneId",
|
|
"ITestConnectId",
|
|
"ITestEncryptId"
|
|
};
|
|
const char *REG_APP_NAME[NUM_CLASS_IDS] =
|
|
{
|
|
"Apartment Application with automatic security set to none",
|
|
"Apartment Application with automatic security set to connect",
|
|
"Apartment Application with automatic security set to integrity",
|
|
"Apartment Application with basic security",
|
|
"Apartment Application with legacy security",
|
|
"FreeThreaded Application with automatic security set to none",
|
|
"FreeThreaded Application with automatic security set to connect",
|
|
"FreeThreaded Application with automatic security set to integrity",
|
|
"FreeThreaded Application with basic security",
|
|
"FreeThreaded Application with legacy security",
|
|
};
|
|
const char *REG_APP_OPTIONS[NUM_CLASS_IDS] =
|
|
{
|
|
" Apartment -auto 1",
|
|
" Apartment -auto 2",
|
|
" Apartment -auto 5",
|
|
" Apartment -basic",
|
|
" Apartment -legacy",
|
|
" Multi -auto 1",
|
|
" Multi -auto 2",
|
|
" Multi -auto 5",
|
|
" Multi -basic",
|
|
" Multi -legacy",
|
|
};
|
|
|
|
// Private symbols needed for the apartment model.
|
|
#define COINIT_MULTITHREADED 0
|
|
#define COINIT_SINGLETHREADED 1
|
|
#define COINIT_APARTMENTTHREADED 2
|
|
|
|
typedef enum
|
|
{
|
|
dirty_s,
|
|
late_dispatch_s
|
|
} state_en;
|
|
|
|
typedef enum what_next_en
|
|
{
|
|
callback_wn,
|
|
catch_wn,
|
|
crippled_wn,
|
|
interrupt_wn,
|
|
interrupt_marshal_wn,
|
|
quit_wn,
|
|
reinitialize_wn,
|
|
rest_and_die_wn,
|
|
setup_wn,
|
|
wait_wn
|
|
} what_next_en;
|
|
|
|
typedef enum
|
|
{
|
|
cancel_wt,
|
|
crash_wt,
|
|
cstress_wt,
|
|
hook_wt,
|
|
load_client_wt,
|
|
load_server_wt,
|
|
lots_wt,
|
|
mmarshal_wt,
|
|
none_wt,
|
|
null_wt,
|
|
one_wt,
|
|
perf_wt,
|
|
perfremote_wt,
|
|
perfrpc_wt,
|
|
perfsec_wt,
|
|
post_wt,
|
|
reject_wt,
|
|
remote_client_wt,
|
|
remote_server_wt,
|
|
ring_wt,
|
|
rpc_wt,
|
|
rundown_wt,
|
|
securerefs_wt,
|
|
security_wt,
|
|
send_wt,
|
|
server_wt,
|
|
sid_wt,
|
|
simple_rundown_wt,
|
|
thread_wt,
|
|
three_wt,
|
|
two_wt,
|
|
uninit_wt,
|
|
unknown_wt
|
|
} what_test_en;
|
|
|
|
typedef enum
|
|
{
|
|
apt_auto_none,
|
|
apt_auto_connect,
|
|
apt_auto_integrity,
|
|
apt_basic,
|
|
apt_legacy,
|
|
free_auto_none,
|
|
free_auto_connect,
|
|
free_auto_integrity,
|
|
free_basic,
|
|
free_legacy
|
|
} class_id_types;
|
|
|
|
typedef enum
|
|
{
|
|
auto_sm,
|
|
basic_sm,
|
|
legacy_sm
|
|
} security_model;
|
|
|
|
typedef struct
|
|
{
|
|
IStream *stream;
|
|
HANDLE ready;
|
|
} new_apt_params;
|
|
|
|
typedef struct
|
|
{
|
|
LONG object_count;
|
|
what_next_en what_next;
|
|
BOOL exit_dirty;
|
|
DWORD sequence;
|
|
} SAptData;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char **buffer;
|
|
long *buf_size;
|
|
RPC_STATUS status;
|
|
ULONG thread;
|
|
} SGetInterface;
|
|
|
|
typedef HRESULT (*INIT_FN)( void *, ULONG );
|
|
|
|
typedef void (*SIMPLE_FN)( void * );
|
|
|
|
typedef HRESULT (*CoInitializeSecurityFn)(
|
|
SECURITY_DESCRIPTOR *pSecDesc,
|
|
DWORD cbAuthSvc,
|
|
SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
|
|
WCHAR *pPrincName,
|
|
DWORD dwAuthnLevel,
|
|
DWORD dwImpLevel,
|
|
RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
|
|
DWORD dwCapabilities,
|
|
void *pReserved );
|
|
typedef HRESULT (*CoQueryAuthenticationServicesFn)( DWORD *pcbAuthSvc,
|
|
SOLE_AUTHENTICATION_SERVICE **asAuthSvc );
|
|
typedef HRESULT (*CoGetCallContextFn)( REFIID riid, void **ppInterface );
|
|
typedef HRESULT (*CoSwitchCallContextFn)( IUnknown *pNewObject, IUnknown **ppOldObject );
|
|
typedef HRESULT (*CoQueryProxyBlanketFn)(
|
|
IUnknown *pProxy,
|
|
DWORD *pwAuthnSvc,
|
|
DWORD *pAuthzSvc,
|
|
OLECHAR **pServerPrincName,
|
|
DWORD *pAuthnLevel,
|
|
DWORD *pImpLevel,
|
|
RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
|
|
DWORD *pCapabilites );
|
|
typedef HRESULT (*CoSetProxyBlanketFn)(
|
|
IUnknown *pProxy,
|
|
DWORD dwAuthnSvc,
|
|
DWORD dwAuthzSvc,
|
|
OLECHAR *pServerPrincName,
|
|
DWORD dwAuthnLevel,
|
|
DWORD dwImpLevel,
|
|
RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
|
|
DWORD dwCapabilities );
|
|
typedef HRESULT (*CoCopyProxyFn)(
|
|
IUnknown *pProxy,
|
|
IUnknown **ppCopy );
|
|
typedef HRESULT (*CoQueryClientBlanketFn)(
|
|
DWORD *pAuthnSvc,
|
|
DWORD *pAuthzSvc,
|
|
OLECHAR **pServerPrincName,
|
|
DWORD *pAuthnLevel,
|
|
DWORD *pImpLevel,
|
|
RPC_AUTHZ_HANDLE *pPrivs,
|
|
DWORD *pCapabilities );
|
|
typedef HRESULT (*CoImpersonateClientFn)();
|
|
typedef HRESULT (*CoRevertToSelfFn)();
|
|
|
|
/***************************************************************************/
|
|
/* Classes */
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Class: CTestCF
|
|
//
|
|
// Synopsis: Class Factory for CTest
|
|
//
|
|
// Methods: IUnknown - QueryInterface, AddRef, Release
|
|
// IClassFactory - CreateInstance
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
|
|
class FAR CTestCF: public IClassFactory
|
|
{
|
|
public:
|
|
|
|
// Constructor/Destructor
|
|
CTestCF();
|
|
~CTestCF();
|
|
|
|
// IUnknown
|
|
STDMETHOD (QueryInterface) (REFIID iid, void FAR * FAR * ppv);
|
|
STDMETHOD_(ULONG,AddRef) ( void );
|
|
STDMETHOD_(ULONG,Release) ( void );
|
|
|
|
// IClassFactory
|
|
STDMETHODIMP CreateInstance(
|
|
IUnknown FAR* pUnkOuter,
|
|
REFIID iidInterface,
|
|
void FAR* FAR* ppv);
|
|
|
|
STDMETHODIMP LockServer(BOOL fLock);
|
|
|
|
private:
|
|
|
|
ULONG ref_count;
|
|
};
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Class: CAdvise
|
|
//
|
|
// Synopsis: Asynchronous test class
|
|
//
|
|
//--------------------------------------------------------------------
|
|
class CAdvise : public IAdviseSink
|
|
{
|
|
public:
|
|
CAdvise();
|
|
~CAdvise();
|
|
|
|
// IUnknown
|
|
STDMETHOD (QueryInterface) (REFIID iid, void FAR * FAR * ppv);
|
|
STDMETHOD_(ULONG,AddRef) ( void );
|
|
STDMETHOD_(ULONG,Release) ( void );
|
|
|
|
// IAdviseSink
|
|
STDMETHODIMP_(void) OnDataChange( FORMATETC *, STGMEDIUM * );
|
|
STDMETHODIMP_(void) OnViewChange( DWORD, LONG );
|
|
STDMETHODIMP_(void) OnRename ( IMoniker * );
|
|
STDMETHODIMP_(void) OnSave ( void );
|
|
STDMETHODIMP_(void) OnClose ( void );
|
|
|
|
private:
|
|
ULONG ref_count;
|
|
};
|
|
|
|
//+----------------------------------------------------------------
|
|
//
|
|
// Class: CHook
|
|
//
|
|
// Purpose: Test channel hooks
|
|
//
|
|
//-----------------------------------------------------------------
|
|
|
|
class CHook : public IChannelHook
|
|
{
|
|
public:
|
|
CHook( REFGUID, DWORD seq );
|
|
|
|
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
|
|
STDMETHOD_(ULONG,AddRef) ( void );
|
|
STDMETHOD_(ULONG,Release) ( void );
|
|
|
|
STDMETHOD_(void,ClientGetSize) ( REFGUID, REFIID, ULONG *DataSize );
|
|
STDMETHOD_(void,ClientFillBuffer)( REFGUID, REFIID, ULONG *DataSize, void *DataBuffer );
|
|
STDMETHOD_(void,ClientNotify) ( REFGUID, REFIID, ULONG DataSize, void *DataBuffer,
|
|
DWORD DataRep, HRESULT );
|
|
STDMETHOD_(void,ServerNotify) ( REFGUID, REFIID, ULONG DataSize, void *DataBuffer,
|
|
DWORD DataRep );
|
|
STDMETHOD_(void,ServerGetSize) ( REFGUID, REFIID, HRESULT, ULONG *DataSize );
|
|
STDMETHOD_(void,ServerFillBuffer)( REFGUID, REFIID, ULONG *DataSize, void *DataBuffer, HRESULT );
|
|
|
|
HRESULT check ( DWORD, DWORD, DWORD, DWORD );
|
|
void check_buf( DWORD size, unsigned char *buf );
|
|
void fill_buf ( DWORD count, unsigned char *buf );
|
|
DWORD get_size ( DWORD count );
|
|
|
|
private:
|
|
ULONG ref_count;
|
|
GUID extent;
|
|
DWORD sequence;
|
|
DWORD client_get;
|
|
DWORD client_fill;
|
|
DWORD client_notify;
|
|
DWORD server_get;
|
|
DWORD server_fill;
|
|
DWORD server_notify;
|
|
HRESULT result;
|
|
};
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Class: CTest
|
|
//
|
|
// Synopsis: Test class
|
|
//
|
|
//--------------------------------------------------------------------
|
|
class CTest: public ITest, public IMessageFilter
|
|
{
|
|
public:
|
|
CTest();
|
|
~CTest();
|
|
|
|
// IUnknown
|
|
STDMETHOD (QueryInterface) (REFIID iid, void FAR * FAR * ppv);
|
|
STDMETHOD_(ULONG,AddRef) ( void );
|
|
STDMETHOD_(ULONG,Release) ( void );
|
|
|
|
// ITest
|
|
STDMETHOD (align) ( unsigned char x[17] );
|
|
STDMETHOD (call_canceled) ( long, long, ITest * );
|
|
STDMETHOD (call_dead) ( void );
|
|
STDMETHOD (call_me_back) ( ITest *obj );
|
|
STDMETHOD (call_next) ( void );
|
|
STDMETHOD (callback) ( void );
|
|
STDMETHOD (cancel) ( void );
|
|
STDMETHOD (cancel_now) ( void );
|
|
STDMETHOD (cancel_pending_call) ( DWORD * );
|
|
STDMETHOD (cancel_stress) ( ITest *obj );
|
|
STDMETHOD (catch_at_top) ( BOOL, ITest *, STRING );
|
|
STDMETHOD (check) ( SAptId );
|
|
STDMETHOD (check_hook) ( DWORD, DWORD, DWORD, DWORD,
|
|
DWORD, DWORD, DWORD, DWORD );
|
|
STDMETHOD (count) ( void );
|
|
STDMETHOD (crash_out) ( transmit_crash * );
|
|
STDMETHOD (delegate) ( ITest *, SAptId, HACKSID * );
|
|
STDMETHOD (exit) ( void );
|
|
STDMETHOD (forget) ( void );
|
|
STDMETHOD (get_advise) ( IAdviseSink ** );
|
|
STDMETHOD (get_data) ( DWORD, unsigned char *, DWORD,
|
|
unsigned char ** );
|
|
STDMETHOD (get_id) ( SAptId * );
|
|
STDMETHOD (get_next) ( ITest **, SAptId * );
|
|
STDMETHOD (get_next_slowly) ( ITest **, SAptId * );
|
|
STDMETHOD (get_obj_from_new_apt) ( ITest **, SAptId * );
|
|
STDMETHOD (get_obj_from_this_apt) ( ITest **, SAptId * );
|
|
STDMETHOD (get_sid) ( HACKSID ** );
|
|
STDMETHOD (interface_in) ( ITest * );
|
|
STDMETHOD (interrupt) ( ITest *, SAptId, BOOL );
|
|
STDMETHOD (interrupt_marshal) ( ITest *, ITest * );
|
|
STDMETHOD (make_acl) ( HACKSID * );
|
|
STDMETHOD (null) ( void );
|
|
STDMETHOD (out) ( ITest ** );
|
|
STDMETHOD (pointer) ( DWORD * );
|
|
STDMETHOD (recurse) ( ITest *, ULONG );
|
|
STDMETHOD (recurse_disconnect) ( ITest *, ULONG );
|
|
STDMETHOD (recurse_excp) ( ITest *, ULONG );
|
|
STDMETHOD (recurse_fatal) ( ITest *, ULONG, ULONG, BOOL );
|
|
STDMETHOD (recurse_fatal_helper) ( ITest *, ULONG, ULONG, BOOL );
|
|
STDMETHOD (recurse_interrupt) ( ITest *, ULONG );
|
|
STDMETHOD (recurse_secure) ( ITest *, ULONG, ULONG, HACKSID * );
|
|
STDMETHOD (register_hook) ( GUID, DWORD );
|
|
STDMETHOD (register_message_filter)( BOOL );
|
|
STDMETHOD (register_rpc) ( WCHAR *, WCHAR ** );
|
|
STDMETHOD (reinitialize) ( void );
|
|
STDMETHOD (reject_next) ( void );
|
|
STDMETHOD (remember) ( ITest *, SAptId );
|
|
STDMETHOD (rest_and_die) ( void );
|
|
STDMETHOD (retry_next) ( void );
|
|
STDMETHOD (ring) ( DWORD );
|
|
STDMETHOD (secure) ( SAptId, DWORD, DWORD, DWORD, DWORD,
|
|
STRING, HACKSID *, DWORD * );
|
|
STDMETHOD (security_performance) ( DWORD *, DWORD *, DWORD *, DWORD * );
|
|
STDMETHOD (set_state) ( DWORD, DWORD );
|
|
STDMETHOD (sick) ( ULONG );
|
|
STDMETHOD (sleep) ( ULONG );
|
|
STDMETHOD (test) ( ULONG );
|
|
|
|
// IMessageFilter
|
|
STDMETHOD_(DWORD,HandleInComingCall)( DWORD, HTASK, DWORD, LPINTERFACEINFO );
|
|
STDMETHOD_(DWORD,MessagePending) ( HTASK, DWORD, DWORD );
|
|
STDMETHOD_(DWORD,RetryRejectedCall) ( HTASK, DWORD, DWORD );
|
|
|
|
// Other
|
|
void assert_unknown();
|
|
|
|
|
|
private:
|
|
|
|
ULONG ref_count;
|
|
SAptId my_id;
|
|
SAptId next_id;
|
|
ITest *next;
|
|
BOOL fcancel_next;
|
|
BOOL freject_next;
|
|
BOOL fretry_next;
|
|
BOOL flate_dispatch;
|
|
};
|
|
|
|
/***************************************************************************/
|
|
/* Prototypes. */
|
|
DWORD _stdcall apartment_base ( void * );
|
|
void check_for_request ( void );
|
|
HRESULT create_instance ( REFCLSID, ITest **, SAptId * );
|
|
void crippled ( void );
|
|
void decrement_object_count ( void );
|
|
BOOL dirty_thread ( void );
|
|
void do_cancel ( void );
|
|
BOOL do_cancel_helper ( ITest *, SAptId, ITest *, SAptId );
|
|
void do_crash ( void );
|
|
BOOL do_crash_helper ( ITest *, SAptId, ITest *, SAptId );
|
|
void do_cstress ( void );
|
|
void do_hook ( void );
|
|
BOOL do_hook_helper ( BOOL, ITest *, SAptId, ITest * );
|
|
void do_load_client ( void );
|
|
void do_load_server ( void );
|
|
void do_mmarshal ( void );
|
|
void do_null ( void );
|
|
void do_one ( void );
|
|
void do_perf ( void );
|
|
void do_perfremote ( void );
|
|
void do_perfrpc ( void );
|
|
void do_perfsec ( void );
|
|
void do_post ( void );
|
|
void do_reject ( void );
|
|
void do_remote_client ( void );
|
|
void do_remote_server ( void );
|
|
void do_ring ( void );
|
|
void do_rpc ( void );
|
|
void do_rundown ( void );
|
|
BOOL do_rundown1 ( ITest **, SAptId *, DWORD );
|
|
BOOL do_rundown2 ( ITest **, SAptId *, DWORD );
|
|
void do_securerefs ( void );
|
|
BOOL do_securerefs_helper ( ITest ** );
|
|
void do_security ( void );
|
|
BOOL do_security_auto ( void );
|
|
BOOL do_security_call ( ITest *, SAptId, DWORD, DWORD,
|
|
DWORD, DWORD, SID * );
|
|
BOOL do_security_copy ( ITest *, SAptId );
|
|
BOOL do_security_delegate ( ITest *, SAptId, ITest *, SAptId );
|
|
BOOL do_security_handle ( ITest *, SAptId );
|
|
BOOL do_security_lazy_call ( ITest *, SAptId, DWORD, DWORD,
|
|
DWORD, DWORD, SID * );
|
|
BOOL do_security_nested ( ITest *, SAptId );
|
|
void do_send ( void );
|
|
void do_sid ( void );
|
|
void do_simple_rundown ( void );
|
|
void do_thread ( void );
|
|
void do_three ( void );
|
|
void do_two ( void );
|
|
void do_uninit ( void );
|
|
DWORD _stdcall do_uninit_helper ( void *param );
|
|
void do_unknown ( void );
|
|
BOOL do_unknown_call ( IUnknown *, DWORD, DWORD, REFIID );
|
|
BOOL do_unknown_helper ( IUnknown *server );
|
|
void *Fixup ( char * );
|
|
WINOLEAPI FixupCoCopyProxy ( IUnknown *, IUnknown ** );
|
|
WINOLEAPI FixupCoGetCallContext ( REFIID, void ** );
|
|
WINOLEAPI FixupCoImpersonateClient ();
|
|
WINOLEAPI FixupCoInitializeSecurity ( SECURITY_DESCRIPTOR *, DWORD, SOLE_AUTHENTICATION_SERVICE *, WCHAR *, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE, DWORD, void * );
|
|
WINOLEAPI FixupCoQueryAuthenticationServices ( DWORD *, SOLE_AUTHENTICATION_SERVICE ** );
|
|
WINOLEAPI FixupCoQueryClientBlanket ( DWORD *, DWORD *, OLECHAR **, DWORD *, DWORD *, RPC_AUTHZ_HANDLE *, DWORD * );
|
|
WINOLEAPI FixupCoQueryProxyBlanket ( IUnknown *, DWORD *, DWORD *, OLECHAR **, DWORD *, DWORD *, RPC_AUTH_IDENTITY_HANDLE *, DWORD * );
|
|
WINOLEAPI FixupCoRevertToSelf ();
|
|
WINOLEAPI FixupCoSetProxyBlanket ( IUnknown *, DWORD, DWORD, OLECHAR *, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE *, DWORD );
|
|
WINOLEAPI FixupCoSwitchCallContext ( IUnknown *, IUnknown ** );
|
|
DWORD get_sequence ( void );
|
|
void hello ( char * );
|
|
void increment_object_count ( void );
|
|
HRESULT initialize ( void *, ULONG );
|
|
HRESULT initialize_security ( void );
|
|
void interrupt ( void );
|
|
HRESULT new_apartment_test ( ITest **, SAptId *, HANDLE * );
|
|
BOOL parse ( int argc, char *argv[] );
|
|
BOOL registry_setup ( char * );
|
|
void reinitialize ( void );
|
|
void server_loop ( void );
|
|
DWORD _stdcall status_helper ( void * );
|
|
HRESULT switch_thread ( SIMPLE_FN, void * );
|
|
void switch_test ( void );
|
|
void thread_get_interface_buffer( handle_t binding, long *buf_size,
|
|
unsigned char **buffer, SAptId *id,
|
|
error_status_t *status );
|
|
DWORD _stdcall thread_helper ( void * );
|
|
void wait_for_message ( void );
|
|
void wake_up_and_smell_the_roses( void );
|
|
void what_next ( what_next_en );
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Externals. */
|
|
const IID ClassIds[NUM_CLASS_IDS] =
|
|
{
|
|
{0x60000000, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000001, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000002, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000003, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000004, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000005, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000006, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000007, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000008, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
{0x60000009, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
|
|
};
|
|
|
|
/* Globals. */
|
|
BOOL Change = FALSE;
|
|
CTestCF *ClassFactory;
|
|
char Debugger[MAX_PATH+MAX_PATH] = "";
|
|
HANDLE Done;
|
|
CoCopyProxyFn GCoCopyProxy = FixupCoCopyProxy;
|
|
CoGetCallContextFn GCoGetCallContext = FixupCoGetCallContext;
|
|
CoImpersonateClientFn GCoImpersonateClient = FixupCoImpersonateClient;
|
|
CoInitializeSecurityFn GCoInitializeSecurity = FixupCoInitializeSecurity;
|
|
CoQueryAuthenticationServicesFn GCoQueryAuthenticationServices = FixupCoQueryAuthenticationServices;
|
|
CoQueryClientBlanketFn GCoQueryClientBlanket = FixupCoQueryClientBlanket;
|
|
CoQueryProxyBlanketFn GCoQueryProxyBlanket = FixupCoQueryProxyBlanket;
|
|
CoRevertToSelfFn GCoRevertToSelf = FixupCoRevertToSelf;
|
|
CoSetProxyBlanketFn GCoSetProxyBlanket = FixupCoSetProxyBlanket;
|
|
CoSwitchCallContextFn GCoSwitchCallContext = FixupCoSwitchCallContext;
|
|
DWORD GlobalAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
|
|
SAptId GlobalApt;
|
|
WCHAR *GlobalBinding;
|
|
BOOL GlobalBool;
|
|
long GlobalCalls = 0;
|
|
long GlobalClients = 0;
|
|
LONG GlobalFirst = TRUE;
|
|
CHook *GlobalHook1 = NULL;
|
|
CHook *GlobalHook2 = NULL;
|
|
BOOL GlobalInterruptTest;
|
|
SECURITY_DESCRIPTOR *GlobalSecurityDescriptor = NULL;
|
|
security_model GlobalSecurityModel = auto_sm;
|
|
ITest *GlobalTest = NULL;
|
|
ITest *GlobalTest2 = NULL;
|
|
ULONG GlobalThreadId = 0;
|
|
long GlobalTotal = 0;
|
|
BOOL GlobalWaiting = FALSE;
|
|
DWORD MainThread;
|
|
BOOL Multicall_Test;
|
|
WCHAR Name[MAX_NAME] = L"";
|
|
DWORD NestedCallCount = 0;
|
|
int NumIterations = 1000;
|
|
int NumObjects = 2;
|
|
int NumProcesses = 2;
|
|
int NumRecursion = 2;
|
|
int NumThreads = 2;
|
|
BOOL Popup = FALSE;
|
|
SAptData ProcessAptData;
|
|
SID *ProcessSid;
|
|
HANDLE RawEvent = NULL;
|
|
HRESULT RawResult;
|
|
DWORD Registration;
|
|
const IID *ServerClsid = &ClassIds[apt_auto_none];
|
|
WCHAR TestProtseq[MAX_NAME] = L"ncadg_ip_udp";
|
|
DWORD ThreadMode = COINIT_APARTMENTTHREADED;
|
|
DWORD TlsIndex;
|
|
what_test_en WhatTest;
|
|
BOOL WriteClass = FALSE;
|
|
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CAdvise::AddRef( THIS )
|
|
{
|
|
InterlockedIncrement( (long *) &ref_count );
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CAdvise::CAdvise()
|
|
{
|
|
ref_count = 1;
|
|
increment_object_count();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CAdvise::~CAdvise()
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CAdvise::OnClose( void )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CAdvise::OnDataChange( FORMATETC *format, STGMEDIUM *stg )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CAdvise::OnRename( IMoniker *moniker )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CAdvise::OnSave( void )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CAdvise::OnViewChange( DWORD aspect, LONG index )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CAdvise::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IAdviseSink))
|
|
{
|
|
*ppvObj = (IUnknown *) (IAdviseSink *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CAdvise::Release( THIS )
|
|
{
|
|
if (InterlockedDecrement( (long*) &ref_count ) == 0)
|
|
{
|
|
decrement_object_count();
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CHook::AddRef( THIS )
|
|
{
|
|
InterlockedIncrement( (long *) &ref_count );
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT CHook::check( DWORD cget, DWORD cnot, DWORD sget, DWORD snot )
|
|
{
|
|
if (result != S_OK)
|
|
return result;
|
|
if (cget != client_get || cnot != client_notify ||
|
|
sget != server_get || snot != server_notify)
|
|
return E_INVALIDARG;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void CHook::check_buf( DWORD size, unsigned char *buf )
|
|
{
|
|
DWORD i;
|
|
|
|
if (sequence == 1)
|
|
{
|
|
if (size == 1)
|
|
{
|
|
if (*buf != 1)
|
|
goto error;
|
|
}
|
|
else if (size == 1000)
|
|
{
|
|
for (i = 0; i < size; i++)
|
|
if (buf[i] != 255)
|
|
goto error;
|
|
}
|
|
else if (size != 0)
|
|
goto error;
|
|
}
|
|
else if (sequence == 2)
|
|
{
|
|
for (i = 0; i < size; i++)
|
|
if (buf[i] != (unsigned char) i)
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
if (size != 42)
|
|
goto error;
|
|
i = 0;
|
|
while (i < 42)
|
|
if (buf[i++] != '4' || buf[i++] != '2')
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
error:
|
|
printf( "Hook got bad data.\n" );
|
|
result = E_UNEXPECTED;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CHook::CHook( REFGUID ext, DWORD seq )
|
|
{
|
|
extent = ext;
|
|
sequence = seq;
|
|
ref_count = 1;
|
|
client_get = 0;
|
|
client_fill = 0;
|
|
client_notify = 0;
|
|
server_get = 0;
|
|
server_fill = 0;
|
|
server_notify = 0;
|
|
result = S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CHook::ClientGetSize( REFGUID ext, REFIID riid,
|
|
ULONG *size )
|
|
{
|
|
// Check the parameters.
|
|
if (extent != ext)
|
|
{
|
|
printf( "Hook received the wrong extent.\n" );
|
|
result = E_FAIL;
|
|
}
|
|
|
|
// Return the correct size for each sequence.
|
|
client_get += 1;
|
|
*size = get_size( client_get );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CHook::ClientFillBuffer( REFGUID ext, REFIID riid,
|
|
ULONG *max, void *buffer )
|
|
{
|
|
DWORD size = get_size( client_get );
|
|
|
|
// Check the parameters.
|
|
if (extent != ext)
|
|
{
|
|
printf( "Hook received the wrong extent.\n" );
|
|
result = E_FAIL;
|
|
}
|
|
else if (*max < size)
|
|
{
|
|
printf( "Hook lost space.\n" );
|
|
result = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Fill the buffer.
|
|
*max = size;
|
|
client_fill += 1;
|
|
fill_buf( client_get, (unsigned char *) buffer );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CHook::ClientNotify( REFGUID ext, REFIID riid,
|
|
ULONG size, void *buffer,
|
|
DWORD data_rep, HRESULT result )
|
|
{
|
|
// Verify the parameters.
|
|
if (extent != ext)
|
|
{
|
|
printf( "Hook received the wrong extent.\n" );
|
|
result = E_FAIL;
|
|
}
|
|
|
|
// Verify the data.
|
|
client_notify += 1;
|
|
if (result == S_OK && buffer != NULL)
|
|
check_buf( size, (unsigned char *) buffer );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void CHook::fill_buf( DWORD count, unsigned char *buffer )
|
|
{
|
|
DWORD size = get_size( count );
|
|
DWORD i;
|
|
|
|
if (sequence == 1)
|
|
{
|
|
if (size == 1)
|
|
*buffer = 1;
|
|
else
|
|
for (i = 0; i < size; i++)
|
|
buffer[i] = 255;
|
|
}
|
|
else if (sequence == 2)
|
|
{
|
|
for (i = 0; i < size; i++)
|
|
buffer[i] = i;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
while (i < 42)
|
|
{
|
|
buffer[i++] = '4';
|
|
buffer[i++] = '2';
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD CHook::get_size( DWORD count )
|
|
{
|
|
DWORD size;
|
|
|
|
if (sequence == 1)
|
|
{
|
|
size = count % 3;
|
|
if (size == 2)
|
|
size = 1000;
|
|
return size;
|
|
}
|
|
else if (sequence == 2)
|
|
return count;
|
|
else
|
|
return 42;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CHook::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IChannelHook))
|
|
{
|
|
*ppvObj = (IUnknown *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CHook::Release( THIS )
|
|
{
|
|
if (InterlockedDecrement( (long*) &ref_count ) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CHook::ServerNotify( REFGUID ext, REFIID riid,
|
|
ULONG size, void *buffer,
|
|
DWORD data_rep )
|
|
{
|
|
// Verify the parameters.
|
|
if (extent != ext)
|
|
{
|
|
printf( "Hook received the wrong extent.\n" );
|
|
result = E_FAIL;
|
|
}
|
|
|
|
// Verify the data.
|
|
server_notify += 1;
|
|
if (result == S_OK && buffer != NULL)
|
|
check_buf( size, (unsigned char *) buffer );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CHook::ServerGetSize( REFGUID ext, REFIID riid, HRESULT hr,
|
|
ULONG *size )
|
|
{
|
|
// Check the parameters.
|
|
if (extent != ext)
|
|
{
|
|
printf( "Hook received the wrong extent.\n" );
|
|
result = E_FAIL;
|
|
}
|
|
|
|
// Return the correct size for each sequence.
|
|
server_get += 1;
|
|
*size = get_size( server_get );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(void) CHook::ServerFillBuffer( REFGUID ext, REFIID riid,
|
|
ULONG *max, void *buffer, HRESULT hr )
|
|
{
|
|
DWORD size = get_size( server_get );
|
|
|
|
// Check the parameters.
|
|
if (extent != ext)
|
|
{
|
|
printf( "Hook received the wrong extent.\n" );
|
|
result = E_FAIL;
|
|
}
|
|
else if (*max < size)
|
|
{
|
|
printf( "Hook lost space.\n" );
|
|
result = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Fill the buffer.
|
|
*max = size;
|
|
server_fill += 1;
|
|
fill_buf( server_get, (unsigned char *) buffer );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CTest::AddRef( THIS )
|
|
{
|
|
assert_unknown();
|
|
InterlockedIncrement( (long *) &ref_count );
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::align( unsigned char x[17] )
|
|
{
|
|
ASSERT_THREAD();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void CTest::assert_unknown()
|
|
{
|
|
if ((ThreadMode == COINIT_SINGLETHREADED ||
|
|
ThreadMode == COINIT_APARTMENTTHREADED) &&
|
|
(my_id.process != GetCurrentProcessId() ||
|
|
my_id.thread != GetCurrentThreadId()))
|
|
{
|
|
printf( "**************************************************************\n" );
|
|
printf( "**************************************************************\n" );
|
|
printf( "* Unknown called on wrong thread. *\n" );
|
|
printf( "**************************************************************\n" );
|
|
printf( "**************************************************************\n" );
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::call_canceled( long recurse, long cancel,
|
|
ITest *callback )
|
|
{
|
|
HRESULT result = S_OK;
|
|
DWORD wakeup;
|
|
DWORD sleep;
|
|
DWORD reason;
|
|
MSG msg;
|
|
ASSERT_THREAD();
|
|
|
|
// If the recursion count isn't zero, call back.
|
|
if (recurse > 0)
|
|
{
|
|
result = callback->call_canceled( recurse-1, cancel, this );
|
|
if (recurse <= cancel)
|
|
{
|
|
if (result != RPC_E_CALL_CANCELED &&
|
|
result != MAKE_WIN32( RPC_S_CALL_CANCELLED ))
|
|
if (result == S_OK)
|
|
return E_FAIL;
|
|
else
|
|
return result;
|
|
result = S_OK;
|
|
}
|
|
else if (result != S_OK)
|
|
return result;
|
|
}
|
|
|
|
// If the cancel count is greater then the recursion count, cancel the
|
|
// object that called me.
|
|
if (cancel > recurse)
|
|
{
|
|
// Give the other object a chance to finish canceling me before I cancel
|
|
// him.
|
|
printf( "Waiting 10 seconds before canceling.\n" );
|
|
Sleep(10000);
|
|
result = next->cancel();
|
|
|
|
// Give the cancel a chance to complete before returning.
|
|
printf( "Waiting 5 seconds for cancel to complete.\n" );
|
|
wakeup = GetCurrentTime() + 5000;
|
|
sleep = 5000;
|
|
do
|
|
{
|
|
reason = MsgWaitForMultipleObjects( 0, NULL, FALSE, sleep, QS_ALLINPUT );
|
|
sleep = wakeup - GetCurrentTime();
|
|
if (sleep > 5000)
|
|
sleep = 0;
|
|
if (reason != WAIT_TIMEOUT)
|
|
if (GetMessageA( &msg, NULL, 0, 0 ))
|
|
{
|
|
TranslateMessage (&msg);
|
|
DispatchMessageA (&msg);
|
|
}
|
|
} while (sleep != 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::call_dead( void )
|
|
{
|
|
HRESULT result;
|
|
ASSERT_THREAD();
|
|
|
|
// Call the server, who is dead by now.
|
|
result = next->check( next_id );
|
|
next->Release();
|
|
next = NULL;
|
|
if (SUCCEEDED(result))
|
|
return E_FAIL;
|
|
else
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::call_me_back( ITest *test )
|
|
{
|
|
ASSERT_THREAD();
|
|
|
|
// Save the global object and tell the driver loop what to do next.
|
|
test->AddRef();
|
|
GlobalTest = test;
|
|
what_next( callback_wn );
|
|
wake_up_and_smell_the_roses();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::call_next( void )
|
|
{
|
|
HRESULT result;
|
|
ASSERT_THREAD();
|
|
|
|
// Call the neighbor.
|
|
return next->check( next_id );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::callback( void )
|
|
{
|
|
ASSERT_THREAD();
|
|
GlobalWaiting = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::cancel()
|
|
{
|
|
HRESULT result;
|
|
DWORD thread;
|
|
ASSERT_THREAD();
|
|
|
|
// Tell my neighbor to cancel the current call next time he receives a
|
|
// message on his message queue.
|
|
result = next->cancel_pending_call( &thread );
|
|
|
|
// Put a message on my neighbor's message queue.
|
|
if (result == S_OK)
|
|
{
|
|
if (!PostThreadMessageA( thread, WM_USER, 0, 0 ))
|
|
return E_FAIL;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::cancel_now()
|
|
{
|
|
HRESULT result;
|
|
|
|
return next->cancel();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::cancel_pending_call( DWORD *thread )
|
|
{
|
|
ASSERT_THREAD();
|
|
fcancel_next = TRUE;
|
|
*thread = GetCurrentThreadId();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::cancel_stress( ITest *obj )
|
|
{
|
|
HRESULT result;
|
|
|
|
ASSERT_THREAD();
|
|
|
|
// If there is an object, ask it to cancel the call to it.
|
|
if (obj != NULL)
|
|
result = obj->cancel_now();
|
|
|
|
// Otherwise ask my neighbor to cancel the call to him.
|
|
else
|
|
// This only works locally.
|
|
result = next->cancel();
|
|
|
|
// Although the call should have been canceled, sometimes it completes
|
|
// before the cancel does.
|
|
if (result == S_OK || result == RPC_E_CALL_CANCELED ||
|
|
result == MAKE_WIN32( RPC_S_CALL_CANCELLED ))
|
|
return S_OK;
|
|
else
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::catch_at_top( BOOL catchme, ITest *callback, STRING binding )
|
|
{
|
|
// Save the callback object and the binding.
|
|
callback->AddRef();
|
|
GlobalTest = callback;
|
|
GlobalBinding = binding;
|
|
|
|
// If the catch flag is true, tell the top level message loop to catch
|
|
// exceptions.
|
|
what_next( catch_wn );
|
|
wake_up_and_smell_the_roses();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::check( SAptId id )
|
|
{
|
|
ASSERT_THREAD();
|
|
if (my_id.process == id.process && my_id.thread == id.thread &&
|
|
my_id.sequence == id.sequence)
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::check_hook( DWORD cg1, DWORD cn1, DWORD sg1, DWORD sn1,
|
|
DWORD cg2, DWORD cn2, DWORD sg2, DWORD sn2 )
|
|
{
|
|
HRESULT result;
|
|
ASSERT_THREAD();
|
|
result = GlobalHook1->check( cg1, cn1, sg1, sn1 );
|
|
if (result == S_OK && GlobalHook2 != NULL)
|
|
result = GlobalHook2->check( cg2, cn2, sg2, sn2 );
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::count()
|
|
{
|
|
InterlockedIncrement( &GlobalCalls );
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::crash_out( transmit_crash *x )
|
|
{
|
|
*x = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CTest::CTest()
|
|
{
|
|
ref_count = 1;
|
|
next = NULL;
|
|
fcancel_next = FALSE;
|
|
freject_next = FALSE;
|
|
fretry_next = FALSE;
|
|
flate_dispatch = FALSE;
|
|
my_id.sequence = get_sequence();
|
|
my_id.thread = GetCurrentThreadId();
|
|
my_id.process = GetCurrentProcessId();
|
|
increment_object_count();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CTest::~CTest()
|
|
{
|
|
if (next != NULL)
|
|
if (!dirty_thread())
|
|
next->Release();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::delegate( ITest *obj, SAptId id, HACKSID *sid )
|
|
{
|
|
HRESULT result = S_OK;
|
|
DWORD ignore;
|
|
|
|
ASSERT_THREAD();
|
|
|
|
// Impersonate.
|
|
result = MCoImpersonateClient();
|
|
ASSERT( result, "Could not impersonate" );
|
|
|
|
// Set the security for the next call.
|
|
result = MCoSetProxyBlanket( obj, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket" );
|
|
|
|
// Call the final server.
|
|
result = obj->secure( id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_NONE, NULL, sid, &ignore );
|
|
ASSERT( result, "Could not make delegate call" );
|
|
|
|
cleanup:
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::exit( void )
|
|
{
|
|
what_next( quit_wn );
|
|
wake_up_and_smell_the_roses();
|
|
ASSERT_THREAD();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::forget( void )
|
|
{
|
|
ASSERT_THREAD();
|
|
if (next != NULL)
|
|
{
|
|
next->Release();
|
|
next = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_advise( IAdviseSink **obj )
|
|
{
|
|
*obj = NULL;
|
|
ASSERT_THREAD();
|
|
*obj = new CAdvise;
|
|
if (*obj!= NULL)
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_data( DWORD isize, unsigned char *idata, DWORD osize,
|
|
unsigned char **odata )
|
|
{
|
|
*odata = (unsigned char *) CoTaskMemAlloc( 1 );
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_id( SAptId *id )
|
|
{
|
|
ASSERT_THREAD();
|
|
*id = my_id;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_next( ITest **obj, SAptId *id )
|
|
{
|
|
*obj = NULL;
|
|
ASSERT_THREAD();
|
|
*id = next_id;
|
|
*obj = next;
|
|
if (next != NULL)
|
|
next->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_next_slowly( ITest **obj, SAptId *id )
|
|
{
|
|
*obj = NULL;
|
|
ASSERT_THREAD();
|
|
*id = next_id;
|
|
*obj = next;
|
|
if (next != NULL)
|
|
next->AddRef();
|
|
|
|
// Start shutting down.
|
|
exit();
|
|
|
|
// Wait a while.
|
|
SetEvent( RawEvent );
|
|
Sleep( 5000 );
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_obj_from_new_apt( ITest **obj, SAptId *id )
|
|
{
|
|
*obj = NULL;
|
|
ASSERT_THREAD();
|
|
return new_apartment_test( obj, id, NULL );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_obj_from_this_apt( ITest **obj, SAptId *id )
|
|
{
|
|
*obj = NULL;
|
|
ASSERT_THREAD();
|
|
*obj = new CTest;
|
|
if (*obj!= NULL)
|
|
return (*obj)->get_id( id );
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::get_sid( HACKSID **sid )
|
|
{
|
|
// Allocate memory to return the sid.
|
|
*sid = (HACKSID *) CoTaskMemAlloc( GetLengthSid( ProcessSid ) );
|
|
if (*sid == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Copy it.
|
|
memcpy( *sid, ProcessSid, GetLengthSid( ProcessSid ) );
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(DWORD) CTest::HandleInComingCall( DWORD type, HTASK task,
|
|
DWORD tick,
|
|
LPINTERFACEINFO info )
|
|
{
|
|
if (freject_next)
|
|
{
|
|
freject_next = FALSE;
|
|
return SERVERCALL_REJECTED;
|
|
}
|
|
|
|
// Accept everything.
|
|
else
|
|
return SERVERCALL_ISHANDLED;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::interface_in( ITest *test )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::interrupt( ITest *param, SAptId id, BOOL go )
|
|
{
|
|
ASSERT_THREAD();
|
|
GlobalInterruptTest = go;
|
|
if (go)
|
|
{
|
|
GlobalTest = param;
|
|
GlobalApt = id;
|
|
GlobalTest->AddRef();
|
|
what_next( interrupt_wn );
|
|
wake_up_and_smell_the_roses();
|
|
}
|
|
else
|
|
what_next( wait_wn );
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::interrupt_marshal( ITest *obj1, ITest *obj2 )
|
|
{
|
|
ASSERT_THREAD();
|
|
GlobalTest = obj1;
|
|
GlobalTest2 = obj2;
|
|
GlobalTest->AddRef();
|
|
GlobalTest2->AddRef();
|
|
what_next( interrupt_marshal_wn );
|
|
wake_up_and_smell_the_roses();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::make_acl( HACKSID *allow )
|
|
{
|
|
BOOL success = FALSE;
|
|
BOOL call_success = FALSE;
|
|
PACL pACLNew = NULL;
|
|
DWORD cbACL = 1024;
|
|
PRIVILEGE_SET set;
|
|
DWORD granted_access;
|
|
BOOL access;
|
|
DWORD privilege_size;
|
|
HANDLE token = NULL;
|
|
HRESULT result = E_FAIL;
|
|
LUID audit;
|
|
TOKEN_PRIVILEGES privilege;
|
|
SID *copy = NULL;
|
|
DWORD length;
|
|
|
|
// Open the process's token.
|
|
call_success = OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
|
|
&token );
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not OpenProcessToken" );
|
|
ASSERT_EXPR( call_success, "Could not OpenProcessToken." );
|
|
|
|
// Lookup the audit privilege.
|
|
call_success = LookupPrivilegeValue( NULL, SE_AUDIT_NAME, &audit );
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not LookupPrivilegeValue" );
|
|
|
|
// Enable it.
|
|
privilege.PrivilegeCount = 1;
|
|
privilege.Privileges[0].Luid = audit;
|
|
privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
AdjustTokenPrivileges( token, FALSE, &privilege, sizeof(privilege), NULL,
|
|
NULL );
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not AdjustTokenPrivileges" );
|
|
|
|
// Copy the SID.
|
|
length = GetLengthSid( (SID *) allow );
|
|
copy = (SID *) malloc( length );
|
|
ASSERT_EXPR( copy != NULL, "Could not allocate memory." );
|
|
memcpy( copy, allow, length );
|
|
|
|
// Initialize a new security descriptor.
|
|
GlobalSecurityDescriptor = (SECURITY_DESCRIPTOR *) LocalAlloc(LPTR,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
ASSERT_EXPR( GlobalSecurityDescriptor != NULL, "Could not allocate memory for the security descriptor." );
|
|
call_success = InitializeSecurityDescriptor(GlobalSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
ASSERT_EXPR( call_success, "InitializeSecurityDescriptor" );
|
|
|
|
// Initialize a new ACL.
|
|
pACLNew = (PACL) LocalAlloc(LPTR, cbACL);
|
|
ASSERT_EXPR( pACLNew != NULL, "LocalAlloc" );
|
|
call_success = InitializeAcl(pACLNew, cbACL, ACL_REVISION2);
|
|
ASSERT_EXPR( call_success, "InitializeAcl" );
|
|
|
|
// Allow read but not write access to the file.
|
|
call_success = AddAccessAllowedAce( pACLNew, ACL_REVISION2, READ_CONTROL,
|
|
copy );
|
|
ASSERT_EXPR( call_success, "AddAccessAllowedAce failed." );
|
|
|
|
// Add a new ACL to the security descriptor.
|
|
call_success = SetSecurityDescriptorDacl(GlobalSecurityDescriptor,
|
|
TRUE, /* fDaclPresent flag */
|
|
pACLNew,
|
|
FALSE);
|
|
result = GetLastError();
|
|
ASSERT( result, "SetSecurityDescriptorDacl failed" );
|
|
ASSERT_EXPR( call_success, "SetSecurityDescriptorDacl failed." );
|
|
|
|
// Set the group.
|
|
call_success = SetSecurityDescriptorGroup( GlobalSecurityDescriptor,
|
|
copy, FALSE );
|
|
ASSERT_EXPR( call_success, "SetSecurityDescriptorGroup failed." );
|
|
|
|
// Set the owner.
|
|
call_success = SetSecurityDescriptorOwner( GlobalSecurityDescriptor,
|
|
copy, FALSE );
|
|
ASSERT_EXPR( call_success, "SetSecurityDescriptorOwner failed." );
|
|
|
|
// Check the security descriptor.
|
|
call_success = IsValidSecurityDescriptor( GlobalSecurityDescriptor );
|
|
ASSERT_EXPR( call_success, "IsValidSecurityDescriptor failed." );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (!success)
|
|
{
|
|
if(GlobalSecurityDescriptor != NULL)
|
|
LocalFree((HLOCAL) GlobalSecurityDescriptor);
|
|
if(pACLNew != NULL)
|
|
LocalFree((HLOCAL) pACLNew);
|
|
if (copy != NULL)
|
|
free( copy );
|
|
}
|
|
|
|
if (token != NULL)
|
|
CloseHandle( token );
|
|
|
|
if (success)
|
|
return S_OK;
|
|
else if (result != S_OK)
|
|
return result;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(DWORD) CTest::MessagePending( HTASK callee, DWORD tick,
|
|
DWORD type )
|
|
{
|
|
if (fcancel_next)
|
|
{
|
|
fcancel_next = FALSE;
|
|
return PENDINGMSG_CANCELCALL;
|
|
}
|
|
else
|
|
return PENDINGMSG_WAITDEFPROCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
HRESULT result = S_OK;
|
|
DWORD query_authn_level;
|
|
BOOL success;
|
|
char value[REGISTRY_ENTRY_LEN];
|
|
LONG value_size = sizeof(value);
|
|
HANDLE token;
|
|
|
|
ASSERT_THREAD();
|
|
*ppvObj = NULL;
|
|
|
|
// Return the normal interfaces.
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_ITest))
|
|
{
|
|
*ppvObj = (IUnknown *) (ITest *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// Return the message filter.
|
|
else if (IsEqualIID(riid, IID_IMessageFilter))
|
|
{
|
|
*ppvObj = (IUnknown *) (IMessageFilter *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// Check security and return ITest.
|
|
else if (IsEqualIID( riid, IID_ITestNoneImp ) ||
|
|
IsEqualIID( riid, IID_ITestConnectImp ) ||
|
|
IsEqualIID( riid, IID_ITestEncryptImp ) ||
|
|
IsEqualIID( riid, IID_ITestNoneId ) ||
|
|
IsEqualIID( riid, IID_ITestConnectId ) ||
|
|
IsEqualIID( riid, IID_ITestEncryptId ))
|
|
{
|
|
// Get the authentication information.
|
|
result = MCoQueryClientBlanket( NULL, NULL, NULL, &query_authn_level,
|
|
NULL, NULL, NULL );
|
|
// Impersonate.
|
|
if (SUCCEEDED(result))
|
|
{
|
|
result = MCoImpersonateClient();
|
|
if (query_authn_level != RPC_C_AUTHN_LEVEL_NONE && FAILED(result))
|
|
return result;
|
|
}
|
|
|
|
// Look at the IID to determine the proper results.
|
|
if (IsEqualIID( riid, IID_ITestNoneImp ))
|
|
{
|
|
// If there is a token, should not be able to read the registry.
|
|
success = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token );
|
|
if (success)
|
|
{
|
|
result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
|
|
if (result != ERROR_SUCCESS)
|
|
goto exit;
|
|
}
|
|
*ppvObj = (ITest *) this;
|
|
AddRef();
|
|
result = S_OK;
|
|
goto exit;
|
|
}
|
|
if (IsEqualIID( riid, IID_ITestConnectImp ))
|
|
{
|
|
// The query and impersonate should have succeeded.
|
|
if (FAILED(result)) return result;
|
|
|
|
// Should be able to read the registry.
|
|
if (query_authn_level < RPC_C_AUTHN_LEVEL_CONNECT)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
|
|
if (result != ERROR_SUCCESS)
|
|
goto exit;
|
|
*ppvObj = (ITest *) this;
|
|
AddRef();
|
|
result = S_OK;
|
|
goto exit;
|
|
}
|
|
if (IsEqualIID( riid, IID_ITestEncryptImp ))
|
|
{
|
|
// The query and impersonate should have succeeded.
|
|
if (FAILED(result)) return result;
|
|
|
|
// Should be able to read the registry.
|
|
if (query_authn_level < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
|
|
if (result != ERROR_SUCCESS)
|
|
goto exit;
|
|
*ppvObj = (ITest *) this;
|
|
AddRef();
|
|
result = S_OK;
|
|
goto exit;
|
|
}
|
|
if (IsEqualIID( riid, IID_ITestNoneId ))
|
|
{
|
|
// If there is a token, should not be able to read the registry.
|
|
success = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token );
|
|
if (success)
|
|
{
|
|
result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
|
|
if (result != ERROR_BAD_IMPERSONATION_LEVEL)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
*ppvObj = (ITest *) this;
|
|
AddRef();
|
|
result = S_OK;
|
|
goto exit;
|
|
}
|
|
if (IsEqualIID( riid, IID_ITestConnectId ))
|
|
{
|
|
// The query and impersonate should have succeeded.
|
|
if (FAILED(result)) return result;
|
|
|
|
// Should not be able to read the registry.
|
|
if (query_authn_level < RPC_C_AUTHN_LEVEL_CONNECT)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
|
|
if (result != ERROR_BAD_IMPERSONATION_LEVEL)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
*ppvObj = (ITest *) this;
|
|
AddRef();
|
|
result = S_OK;
|
|
goto exit;
|
|
}
|
|
if (IsEqualIID( riid, IID_ITestEncryptId ))
|
|
{
|
|
// The query and impersonate should have succeeded.
|
|
if (FAILED(result)) return result;
|
|
|
|
// Should be able to read the registry.
|
|
if (query_authn_level < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
|
|
if (result != ERROR_BAD_IMPERSONATION_LEVEL)
|
|
{
|
|
result = E_FAIL;
|
|
goto exit;
|
|
}
|
|
*ppvObj = (ITest *) this;
|
|
AddRef();
|
|
result = S_OK;
|
|
goto exit;
|
|
}
|
|
exit:
|
|
CoRevertToSelf();
|
|
return result;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::null()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::out( ITest **obj )
|
|
{
|
|
*obj = this;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::pointer( DWORD *p )
|
|
{
|
|
ASSERT_THREAD();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse( ITest *callback, ULONG depth )
|
|
{
|
|
ASSERT_THREAD();
|
|
if (depth == 0)
|
|
return S_OK;
|
|
else
|
|
return callback->recurse( this, depth-1 );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse_disconnect( ITest *callback, ULONG depth )
|
|
{
|
|
ASSERT_THREAD();
|
|
|
|
HRESULT result;
|
|
|
|
if (depth == 0)
|
|
{
|
|
result = CoDisconnectObject( (ITest *) this, 0 );
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
result = callback->recurse_disconnect( this, depth-1 );
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse_excp( ITest *callback, ULONG depth )
|
|
{
|
|
ASSERT_THREAD();
|
|
if (depth == 0)
|
|
{
|
|
RaiseException( E_FAIL, 0, 0, NULL );
|
|
return E_FAIL;
|
|
}
|
|
else
|
|
return callback->recurse_excp( this, depth-1 );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse_fatal( ITest *callback, ULONG catch_depth,
|
|
ULONG throw_depth, BOOL cancel )
|
|
{
|
|
ASSERT_THREAD();
|
|
if (catch_depth == 0)
|
|
{
|
|
__try
|
|
{
|
|
return recurse_fatal_helper( callback, catch_depth, throw_depth, cancel );
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
printf( "Exception on thread 0x%x\n", GetCurrentThreadId() );
|
|
what_next( crippled_wn );
|
|
wake_up_and_smell_the_roses();
|
|
return S_OK;
|
|
}
|
|
}
|
|
else
|
|
return recurse_fatal_helper( callback, catch_depth, throw_depth, cancel );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse_fatal_helper( ITest *callback, ULONG catch_depth,
|
|
ULONG throw_depth, BOOL cancel )
|
|
{
|
|
volatile void **p = (volatile void **) 0xffffffff;
|
|
|
|
if (throw_depth == 0)
|
|
{
|
|
// If the cancel flag is set, tell the helper to tell the caller to cancel
|
|
// the call to this object.
|
|
if (cancel)
|
|
next->cancel();
|
|
|
|
// Die a horrible death.
|
|
return (HRESULT) *p;
|
|
}
|
|
else
|
|
return callback->recurse_fatal( this, catch_depth-1, throw_depth-1, cancel );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse_interrupt( ITest *callback, ULONG depth )
|
|
{
|
|
MSG msg;
|
|
|
|
ASSERT_THREAD();
|
|
if (PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE ))
|
|
{
|
|
TranslateMessage (&msg);
|
|
DispatchMessageA (&msg);
|
|
}
|
|
|
|
if (depth == 0)
|
|
return S_OK;
|
|
else
|
|
return callback->recurse( this, depth-1 );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::recurse_secure( ITest *callback, ULONG depth,
|
|
ULONG imp_depth, HACKSID *sid )
|
|
{
|
|
HRESULT result;
|
|
TOKEN_USER *token_info = NULL;
|
|
DWORD info_size = 1024;
|
|
HANDLE token = NULL;
|
|
PSID me = NULL;
|
|
ASSERT_THREAD();
|
|
|
|
if (depth != 0)
|
|
{
|
|
// Set the authentication level to connect.
|
|
result = MCoSetProxyBlanket( callback, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket" );
|
|
}
|
|
|
|
// Impersonate if necessary.
|
|
if (imp_depth == 0)
|
|
{
|
|
result = MCoImpersonateClient();
|
|
ASSERT( result, "Could not impersonate" );
|
|
}
|
|
|
|
// If not deep enough, continue to recurse.
|
|
if (depth != 0)
|
|
{
|
|
result = callback->recurse_secure( this, depth-1, imp_depth-1,
|
|
(HACKSID *) ProcessSid );
|
|
ASSERT( result, "Could not recurse" );
|
|
}
|
|
|
|
// Open the thread's token.
|
|
if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
if (imp_depth == 0)
|
|
{
|
|
ASSERT( result, "Could not open thread token while impersonating" );
|
|
}
|
|
else
|
|
{
|
|
ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
|
|
}
|
|
|
|
// Lookup SID of thread token.
|
|
token_info = (TOKEN_USER *) malloc( info_size );
|
|
if (token_info == NULL)
|
|
{
|
|
result = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
if (result == NOERROR)
|
|
{
|
|
if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
me = token_info->User.Sid;
|
|
CloseHandle( token );
|
|
token = NULL;
|
|
|
|
// Check the SID in the thread token.
|
|
if (imp_depth == 0)
|
|
{
|
|
if (!EqualSid( me, sid ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!EqualSid( me, ProcessSid ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Revert.
|
|
if (imp_depth != 0)
|
|
{
|
|
result = MCoRevertToSelf();
|
|
ASSERT( result, "Could not revert" );
|
|
}
|
|
|
|
// Open the thread's token.
|
|
if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
if (imp_depth == 0)
|
|
{
|
|
ASSERT( result, "Could not open thread token while impersonating" );
|
|
}
|
|
else
|
|
{
|
|
ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
|
|
}
|
|
|
|
// Lookup SID of thread token.
|
|
if (result == NOERROR)
|
|
{
|
|
if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
me = token_info->User.Sid;
|
|
CloseHandle( token );
|
|
token = NULL;
|
|
|
|
// Check the SID in the thread token.
|
|
if (imp_depth == 0)
|
|
{
|
|
if (!EqualSid( me, sid ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!EqualSid( me, ProcessSid ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
result = S_OK;
|
|
cleanup:
|
|
if (token_info != NULL)
|
|
free(token_info);
|
|
if (token != NULL)
|
|
CloseHandle( token );
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CTest::Release( THIS )
|
|
{
|
|
DWORD status;
|
|
|
|
assert_unknown();
|
|
if (InterlockedDecrement( (long*) &ref_count ) == 0)
|
|
{
|
|
decrement_object_count();
|
|
if (flate_dispatch)
|
|
{
|
|
status = WaitForSingleObject( RawEvent, INFINITE );
|
|
if (status != WAIT_OBJECT_0)
|
|
printf( "WaitForSingleObject failed.\n" );
|
|
}
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::register_hook( GUID ext, DWORD seq )
|
|
{
|
|
CHook *hook;
|
|
ASSERT_THREAD();
|
|
|
|
// Create a new hook.
|
|
hook = new CHook( ext, seq );
|
|
if (hook == NULL)
|
|
return E_OUTOFMEMORY;
|
|
if (GlobalHook1 == NULL)
|
|
GlobalHook1 = hook;
|
|
else
|
|
GlobalHook2 = hook;
|
|
|
|
// Register it.
|
|
return CoRegisterChannelHook( ext, hook );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::register_message_filter( BOOL reg )
|
|
{
|
|
ASSERT_THREAD();
|
|
|
|
if (reg)
|
|
return CoRegisterMessageFilter( this, NULL );
|
|
else
|
|
return CoRegisterMessageFilter( NULL, NULL );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::register_rpc( WCHAR *protseq, WCHAR **binding )
|
|
{
|
|
ASSERT_THREAD();
|
|
|
|
RPC_STATUS status;
|
|
RPC_BINDING_VECTOR *bindings;
|
|
WCHAR *string;
|
|
DWORD i;
|
|
WCHAR *binding_protseq;
|
|
BOOL found;
|
|
|
|
*binding = NULL;
|
|
status = RpcServerUseProtseqEp( protseq, 20, NULL, NULL );
|
|
if (status != RPC_S_OK)
|
|
return MAKE_WIN32( status );
|
|
|
|
status = RpcServerRegisterIf(xIDog_v0_1_s_ifspec,
|
|
NULL, // MgrTypeUuid
|
|
NULL); // MgrEpv; null means use default
|
|
if (status != RPC_S_OK)
|
|
return MAKE_WIN32( status );
|
|
|
|
status = RpcServerRegisterAuthInfo( L"none", RPC_C_AUTHN_WINNT, 0, 0 );
|
|
if (status != RPC_S_OK)
|
|
return MAKE_WIN32( status );
|
|
|
|
status = RpcServerListen( 1, 1235, TRUE );
|
|
if (status != RPC_S_OK && status != RPC_S_ALREADY_LISTENING)
|
|
return MAKE_WIN32( status );
|
|
|
|
// Inquire the string bindings.
|
|
status = RpcServerInqBindings( &bindings );
|
|
if (status != RPC_S_OK)
|
|
return MAKE_WIN32( status );
|
|
if (bindings->Count == 0)
|
|
{
|
|
RpcBindingVectorFree( &bindings );
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Look for ncalrpc.
|
|
for (i = 0; i < bindings->Count; i++)
|
|
{
|
|
|
|
// Convert the binding handle to a string binding, copy it, and free it.
|
|
status = RpcBindingToStringBinding( bindings->BindingH[i], &string );
|
|
if (status == RPC_S_OK)
|
|
{
|
|
// Look up the protseq.
|
|
status = RpcStringBindingParse( string, NULL, &binding_protseq,
|
|
NULL, NULL, NULL );
|
|
if (status == RPC_S_OK)
|
|
{
|
|
found = wcscmp( binding_protseq, protseq ) == 0;
|
|
RpcStringFree( &binding_protseq );
|
|
if (found)
|
|
{
|
|
*binding = (WCHAR *) CoTaskMemAlloc( (wcslen(string)+1) * sizeof(WCHAR) );
|
|
if (*binding != NULL)
|
|
wcscpy( *binding, string );
|
|
else
|
|
status = RPC_S_OUT_OF_RESOURCES;
|
|
RpcStringFree( &string );
|
|
break;
|
|
}
|
|
}
|
|
RpcStringFree( &string );
|
|
}
|
|
}
|
|
if (*binding == NULL)
|
|
status = E_FAIL;
|
|
|
|
// Free the binding vector.
|
|
RpcBindingVectorFree( &bindings );
|
|
return status;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::reject_next()
|
|
{
|
|
freject_next = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::reinitialize()
|
|
{
|
|
ASSERT_THREAD();
|
|
what_next( reinitialize_wn );
|
|
wake_up_and_smell_the_roses();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::remember( ITest *neighbor, SAptId id )
|
|
{
|
|
ASSERT_THREAD();
|
|
|
|
// Save this interface pointer.
|
|
if (next != NULL)
|
|
next->Release();
|
|
next_id = id;
|
|
next = neighbor;
|
|
next->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::rest_and_die()
|
|
{
|
|
ASSERT_THREAD();
|
|
what_next( rest_and_die_wn );
|
|
wake_up_and_smell_the_roses();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::retry_next()
|
|
{
|
|
fretry_next = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(DWORD) CTest::RetryRejectedCall( HTASK callee, DWORD tick,
|
|
DWORD reject )
|
|
{
|
|
if (fretry_next)
|
|
{
|
|
fretry_next = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
// Never retry.
|
|
else
|
|
return 0xffffffff;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::ring( DWORD length )
|
|
{
|
|
DWORD i = 0;
|
|
ITest *ring;
|
|
ITest *ring_next;
|
|
SAptId ring_id;
|
|
HRESULT result;
|
|
|
|
ASSERT_THREAD();
|
|
|
|
// Call all the neighbors in the ring.
|
|
ring = next;
|
|
ring_id = next_id;
|
|
next->AddRef();
|
|
while (ring != this)
|
|
{
|
|
result = ring->check( ring_id );
|
|
if (FAILED(result))
|
|
{
|
|
ring->Release();
|
|
return result;
|
|
}
|
|
result = ring->get_next( &ring_next, &ring_id );
|
|
if (FAILED(result))
|
|
{
|
|
ring->Release();
|
|
return result;
|
|
}
|
|
ring->Release();
|
|
ring = ring_next;
|
|
i++;
|
|
}
|
|
|
|
// Check to make sure the ring is correct.
|
|
ring->Release();
|
|
if (i+1 != length || ring_id.process != my_id.process ||
|
|
ring_id.thread != my_id.thread || ring_id.sequence != my_id.sequence)
|
|
return E_FAIL;
|
|
else
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::secure( SAptId id, DWORD authn_level, DWORD imp_level,
|
|
DWORD authn_svc, DWORD authz_svc,
|
|
STRING princ_name, HACKSID *caller,
|
|
DWORD *authn_level_out )
|
|
{
|
|
HRESULT result = S_OK;
|
|
DWORD query_authn_level;
|
|
DWORD query_imp_level;
|
|
DWORD query_authn_svc;
|
|
DWORD query_authz_svc;
|
|
STRING query_princ_name = NULL;
|
|
TOKEN_USER *token_info = NULL;
|
|
DWORD info_size = 1024;
|
|
HANDLE token = NULL;
|
|
PSID me = NULL;
|
|
|
|
*authn_level_out = RPC_C_AUTHN_LEVEL_NONE;
|
|
|
|
ASSERT_THREAD();
|
|
if (my_id.process != id.process || my_id.thread != id.thread ||
|
|
my_id.sequence != id.sequence)
|
|
return E_FAIL;
|
|
|
|
// Query for the authentication information.
|
|
result = MCoQueryClientBlanket( &query_authn_svc, &query_authz_svc,
|
|
&query_princ_name, &query_authn_level,
|
|
&query_imp_level, NULL, NULL );
|
|
*authn_level_out = query_authn_level;
|
|
|
|
// For unsecure calls, all the other fields should be clear.
|
|
if (authn_level == RPC_C_AUTHN_LEVEL_NONE)
|
|
{
|
|
if (result == S_OK)
|
|
{
|
|
if (query_authn_level < authn_level)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
// The impersonation level can't be determined on the server.
|
|
// if (query_imp_level != RPC_C_IMP_LEVEL_IMPERSONATE)
|
|
if (query_imp_level != RPC_C_IMP_LEVEL_ANONYMOUS)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
if (query_authn_svc != RPC_C_AUTHN_NONE &&
|
|
query_authn_svc != RPC_C_AUTHN_WINNT)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
if (query_authz_svc != RPC_C_AUTHZ_NONE)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
/*
|
|
if ((princ_name == NULL && query_princ_name != NULL) ||
|
|
(princ_name != NULL && query_princ_name == NULL))
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
if (princ_name != NULL &&
|
|
wcscmp(princ_name, query_princ_name) != 0)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
// For secure calls, verify all the authnetication info.
|
|
else
|
|
{
|
|
ASSERT( result, "Could not query client blanket" );
|
|
if (query_authn_level < authn_level)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
// The impersonation level can't be determined on the server.
|
|
//if (query_imp_level != imp_level)
|
|
if (query_imp_level != RPC_C_IMP_LEVEL_ANONYMOUS)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
// Sometimes ncalrpc doesn't set the authentication service.
|
|
if (query_authn_svc != RPC_C_AUTHN_NONE &&
|
|
query_authn_svc != authn_svc)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
if (query_authz_svc != authz_svc)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
/*
|
|
if ((princ_name == NULL && query_princ_name != NULL) ||
|
|
(princ_name != NULL && query_princ_name == NULL))
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
if (princ_name != NULL &&
|
|
wcscmp(princ_name, query_princ_name) != 0)
|
|
{
|
|
result = E_INVALIDARG;
|
|
goto cleanup;
|
|
}
|
|
*/
|
|
}
|
|
|
|
// Open the thread's token.
|
|
if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
|
|
|
|
// Lookup SID of thread token.
|
|
token_info = (TOKEN_USER *) malloc( info_size );
|
|
if (token_info == NULL)
|
|
{
|
|
result = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
if (result == NOERROR)
|
|
{
|
|
if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
me = token_info->User.Sid;
|
|
CloseHandle( token );
|
|
token = NULL;
|
|
|
|
// The SID on the thread token should equal the process token.
|
|
if (!EqualSid( me, ProcessSid ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// Impersonate.
|
|
result = MCoImpersonateClient();
|
|
|
|
// For unsecure calls the impersonate should fail.
|
|
if (authn_level == RPC_C_AUTHN_LEVEL_NONE)
|
|
{
|
|
// Currently the impersonate succeeds without setting the thread token.
|
|
/*
|
|
if (result == S_OK)
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
*/
|
|
result = S_OK;
|
|
}
|
|
|
|
// For secure calls, compare the new thread token sid to the passed
|
|
// in sid.
|
|
else
|
|
{
|
|
ASSERT( result, "Could not impersonate" );
|
|
|
|
// Open the thread's token.
|
|
if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not OpenThreadToken" );
|
|
|
|
// Lookup SID of thread token.
|
|
if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
me = token_info->User.Sid;
|
|
CloseHandle( token );
|
|
token = NULL;
|
|
|
|
// Compare the impersonate sid to the passed in sid.
|
|
if (!EqualSid( me, caller ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// Revert.
|
|
result = MCoRevertToSelf();
|
|
ASSERT( result, "Could not revert" );
|
|
|
|
// Open the thread's token.
|
|
if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
|
|
|
|
// Lookup SID of thread token.
|
|
if (result == NOERROR)
|
|
{
|
|
if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
me = token_info->User.Sid;
|
|
CloseHandle( token );
|
|
token = NULL;
|
|
|
|
// The SID on the thread token should equal the process token.
|
|
if (!EqualSid( me, ProcessSid ))
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
result = S_OK;
|
|
|
|
cleanup:
|
|
if (token_info != NULL)
|
|
free(token_info);
|
|
if (token != NULL)
|
|
CloseHandle( token );
|
|
CoTaskMemFree( query_princ_name );
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::security_performance( DWORD *get_call, DWORD *query_client,
|
|
DWORD *impersonate, DWORD *revert )
|
|
{
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER qget_call;
|
|
LARGE_INTEGER qquery_client;
|
|
LARGE_INTEGER qimpersonate;
|
|
LARGE_INTEGER qrevert;
|
|
LARGE_INTEGER freq;
|
|
IServerSecurity *server_sec = NULL;
|
|
HRESULT result;
|
|
DWORD authn_svc;
|
|
DWORD authz_svc;
|
|
DWORD authn_level;
|
|
DWORD imp_level;
|
|
DWORD capabilities;
|
|
WCHAR *principal = NULL;
|
|
void *privs;
|
|
|
|
// Import the security APIs.
|
|
GCoGetCallContext = (CoGetCallContextFn) Fixup( "CoGetCallContext" );
|
|
GCoImpersonateClient = (CoImpersonateClientFn) Fixup( "CoImpersonateClient" );
|
|
GCoQueryClientBlanket = (CoQueryClientBlanketFn) Fixup( "CoQueryClientBlanket" );
|
|
GCoRevertToSelf = (CoRevertToSelfFn) Fixup( "CoRevertToSelf" );
|
|
if (GCoGetCallContext == NULL ||
|
|
GCoImpersonateClient == NULL ||
|
|
GCoQueryClientBlanket == NULL ||
|
|
GCoRevertToSelf == NULL)
|
|
return E_NOTIMPL;
|
|
|
|
// Measure the performance of get call context.
|
|
QueryPerformanceFrequency( &freq );
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoGetCallContext( IID_IServerSecurity, (void **) &server_sec );
|
|
QueryPerformanceCounter( &qget_call );
|
|
qget_call.QuadPart = 1000000 * (qget_call.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not get call context" );
|
|
server_sec->Release();
|
|
|
|
// Measure the performance of query client.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoQueryClientBlanket( &authn_svc, &authz_svc, &principal,
|
|
&authn_level, &imp_level, &privs, &capabilities );
|
|
QueryPerformanceCounter( &qquery_client );
|
|
qquery_client.QuadPart = 1000000 * (qquery_client.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not query client blanket" );
|
|
CoTaskMemFree( principal );
|
|
|
|
// Measure the performance of impersonate.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoImpersonateClient();
|
|
QueryPerformanceCounter( &qimpersonate );
|
|
qimpersonate.QuadPart = 1000000 * (qimpersonate.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not impersonate" );
|
|
|
|
// Measure the performance of revert.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoRevertToSelf();
|
|
QueryPerformanceCounter( &qrevert );
|
|
qrevert.QuadPart = 1000000 * (qrevert.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not revert" );
|
|
|
|
// Return the results.
|
|
*get_call = qget_call.u.LowPart;
|
|
*query_client = qquery_client.u.LowPart;
|
|
*impersonate = qimpersonate.u.LowPart;
|
|
*revert = qrevert.u.LowPart;
|
|
|
|
cleanup:
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::set_state( DWORD state, DWORD priority )
|
|
{
|
|
BOOL success;
|
|
ASSERT_THREAD();
|
|
|
|
// Save dirty flag per apartment.
|
|
if (state & dirty_s)
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
ProcessAptData.exit_dirty = TRUE;
|
|
else
|
|
{
|
|
SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
|
|
tls_data->exit_dirty = TRUE;
|
|
}
|
|
|
|
// Save the late dispatch flag per object.
|
|
if (state & late_dispatch_s)
|
|
flate_dispatch = TRUE;
|
|
|
|
// Set the priority.
|
|
success = SetThreadPriority( GetCurrentThread(), priority );
|
|
if (success)
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::sick( ULONG val )
|
|
{
|
|
ASSERT_THREAD();
|
|
__try
|
|
{
|
|
RaiseException( val, 0, 0, NULL );
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::sleep( ULONG time )
|
|
{
|
|
ASSERT_THREAD();
|
|
|
|
NestedCallCount += 1;
|
|
printf( "Sleeping on thread %d for the %d time concurrently.\n",
|
|
GetCurrentThreadId(), NestedCallCount );
|
|
|
|
// For multithreaded mode, verify that this is not the main thread.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
if (GetCurrentThreadId() == MainThread)
|
|
{
|
|
printf( "Sleep called on the main thread in multi threaded mode.\n" );
|
|
NestedCallCount -= 1;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// For single threaded mode, verify that this is the only call on the
|
|
// main thread.
|
|
else
|
|
{
|
|
if (GetCurrentThreadId() != MainThread)
|
|
{
|
|
printf( "Sleep called on the wrong thread in single threaded mode.\n" );
|
|
NestedCallCount -= 1;
|
|
return FALSE;
|
|
}
|
|
else if (NestedCallCount != 1)
|
|
{
|
|
printf( "Sleep nested call count is %d instead of not 1 in single threaded mode.\n",
|
|
NestedCallCount );
|
|
NestedCallCount -= 1;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
Sleep( time );
|
|
NestedCallCount -= 1;
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTest::test( ULONG gronk )
|
|
{
|
|
IStream *stream = (IStream *) gronk;
|
|
ITest *server = NULL;
|
|
HRESULT result;
|
|
|
|
// Unmarshal from the stream.
|
|
result = CoGetInterfaceAndReleaseStream( stream, IID_ITest, (void **) &server );
|
|
if (result != S_OK)
|
|
return result;
|
|
|
|
// Release the server.
|
|
server->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CTestCF::AddRef( THIS )
|
|
{
|
|
InterlockedIncrement( (long *) &ref_count );
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CTestCF::CTestCF()
|
|
{
|
|
ref_count = 1;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
CTestCF::~CTestCF()
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTestCF::CreateInstance(
|
|
IUnknown FAR* pUnkOuter,
|
|
REFIID iidInterface,
|
|
void FAR* FAR* ppv)
|
|
{
|
|
*ppv = NULL;
|
|
if (pUnkOuter != NULL)
|
|
{
|
|
printf( "Create instance failed, attempted agregation.\n" );
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (IsEqualIID( iidInterface, IID_ITest ) ||
|
|
IsEqualIID( iidInterface, IID_IUnknown ))
|
|
{
|
|
CTest *Test = new FAR CTest();
|
|
|
|
if (Test == NULL)
|
|
{
|
|
printf( "Create interface failed, no memory.\n" );
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppv = Test;
|
|
printf( "Created instance.\n" );
|
|
return S_OK;
|
|
}
|
|
|
|
if (IsEqualIID( iidInterface, IID_IAdviseSink ))
|
|
{
|
|
CAdvise *Test = new FAR CAdvise();
|
|
|
|
if (Test == NULL)
|
|
{
|
|
printf( "Create interface failed, no memory.\n" );
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppv = Test;
|
|
printf( "Created instance.\n" );
|
|
return S_OK;
|
|
}
|
|
|
|
printf( "Create interface failed, wrong interface.\n" );
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTestCF::LockServer(BOOL fLock)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP CTestCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IClassFactory))
|
|
{
|
|
*ppvObj = (IUnknown *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
STDMETHODIMP_(ULONG) CTestCF::Release( THIS )
|
|
{
|
|
if (InterlockedDecrement( (long*) &ref_count ) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return ref_count;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD _stdcall apartment_base( void *param )
|
|
{
|
|
new_apt_params *nap = (new_apt_params *) param;
|
|
CTestCF *factory;
|
|
ULONG size;
|
|
HRESULT result;
|
|
HANDLE memory;
|
|
BOOL success;
|
|
SAptData tls_data;
|
|
|
|
// In the single threaded mode, stick a pointer to the object count
|
|
// in TLS.
|
|
tls_data.object_count = 0;
|
|
tls_data.what_next = setup_wn;
|
|
tls_data.exit_dirty = FALSE;
|
|
tls_data.sequence = 0;
|
|
TlsSetValue( TlsIndex, &tls_data );
|
|
|
|
// Initialize OLE.
|
|
printf( "Initializing thread 0x%x\n", GetCurrentThreadId() );
|
|
result = initialize(NULL,ThreadMode);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
|
|
// Create a class factory.
|
|
factory = new CTestCF;
|
|
|
|
if (factory != NULL)
|
|
{
|
|
// Find out how much memory to allocate.
|
|
result = CoGetMarshalSizeMax( &size, IID_IClassFactory, factory, 0, NULL,
|
|
MSHLFLAGS_NORMAL );
|
|
|
|
if (SUCCEEDED(result))
|
|
{
|
|
// Allocate memory.
|
|
memory = GlobalAlloc( GMEM_FIXED, size );
|
|
|
|
if (memory != NULL)
|
|
{
|
|
// Create a stream.
|
|
result = CreateStreamOnHGlobal( memory, TRUE, &nap->stream );
|
|
if (FAILED(result))
|
|
{
|
|
nap->stream = NULL;
|
|
GlobalFree( memory );
|
|
}
|
|
|
|
// Marshal the class factory.
|
|
else
|
|
{
|
|
result = CoMarshalInterface( nap->stream, IID_IClassFactory,
|
|
factory, 0, NULL, MSHLFLAGS_NORMAL );
|
|
|
|
// Seek back to the start of the stream.
|
|
if (SUCCEEDED(result))
|
|
{
|
|
LARGE_INTEGER pos;
|
|
LISet32(pos, 0);
|
|
result = nap->stream->Seek( pos, STREAM_SEEK_SET, NULL );
|
|
}
|
|
|
|
if (FAILED(result))
|
|
{
|
|
nap->stream->Release();
|
|
nap->stream = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pass it back to the creator.
|
|
success = nap->stream != NULL;
|
|
SetEvent( nap->ready );
|
|
|
|
// Loop till it is time to go away.
|
|
if (success)
|
|
server_loop();
|
|
if (!dirty_thread())
|
|
{
|
|
printf( "Uninitializing thread 0x%x\n", GetCurrentThreadId() );
|
|
CoUninitialize();
|
|
}
|
|
else
|
|
printf( "Did not uninitialize thread 0x%x\n", GetCurrentThreadId() );
|
|
TlsSetValue( TlsIndex, NULL );
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void callback()
|
|
{
|
|
HRESULT result;
|
|
|
|
// Call the client back.
|
|
Sleep(1);
|
|
result = GlobalTest->callback();
|
|
if (result != S_OK)
|
|
printf( "Could not callback client: 0x%x\n", result );
|
|
|
|
// Release the client.
|
|
GlobalTest->Release();
|
|
GlobalTest = NULL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void check_for_request()
|
|
{
|
|
MSG msg;
|
|
|
|
if (ThreadMode == COINIT_SINGLETHREADED ||
|
|
ThreadMode == COINIT_APARTMENTTHREADED)
|
|
{
|
|
if (PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE ))
|
|
{
|
|
TranslateMessage (&msg);
|
|
DispatchMessageA (&msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT create_instance( REFCLSID class_id, ITest **instance, SAptId *id )
|
|
{
|
|
COSERVERINFO server_machine;
|
|
MULTI_QI server_instance;
|
|
WCHAR this_machine[MAX_NAME];
|
|
DWORD ignore;
|
|
HRESULT result;
|
|
|
|
// Lookup this machine's name.
|
|
*instance = NULL;
|
|
ignore = sizeof(this_machine);
|
|
GetComputerName( this_machine, &ignore );
|
|
|
|
// If the server is this machine, just call CoCreateInstance.
|
|
if (wcscmp(this_machine, Name) == 0)
|
|
result = CoCreateInstance( class_id, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) instance );
|
|
|
|
// Otherwise call CoCreateInstanceEx.
|
|
else
|
|
{
|
|
server_machine.dwReserved1 = 0;
|
|
server_machine.pwszName = Name;
|
|
server_machine.pAuthInfo = 0;
|
|
server_machine.dwReserved2 = 0;
|
|
server_instance.pIID = &IID_ITest;
|
|
server_instance.pItf = NULL;
|
|
server_instance.hr = S_OK;
|
|
result = CoCreateInstanceEx( class_id, NULL, CLSCTX_REMOTE_SERVER,
|
|
&server_machine, 1, &server_instance );
|
|
*instance = (ITest *) server_instance.pItf;
|
|
}
|
|
|
|
// Get the server's id.
|
|
if (SUCCEEDED(result) && *instance != NULL)
|
|
result = (*instance)->get_id( id );
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void crippled()
|
|
{
|
|
HRESULT result;
|
|
SAptData *mine;
|
|
SAptId id;
|
|
RPC_BINDING_HANDLE handle = NULL;
|
|
RPC_STATUS status;
|
|
CTest local;
|
|
|
|
// Get the apartment specific data.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
mine = &ProcessAptData;
|
|
else
|
|
mine = (SAptData *) TlsGetValue( TlsIndex );
|
|
mine->what_next = quit_wn;
|
|
|
|
// Try to make a call out.
|
|
result = GlobalTest->check( id );
|
|
#if 0
|
|
if (result != RPC_E_CRIPPLED)
|
|
{
|
|
printf( "Expected RPC_E_CRIPPLED making call: 0x%x\n", result );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
#endif
|
|
|
|
// Try to reinitialize.
|
|
CoUninitialize();
|
|
result = initialize(NULL,ThreadMode);
|
|
if (result != CO_E_INIT_RPC_CHANNEL)
|
|
{
|
|
printf( "Expected CO_E_INIT_RPC_CHANNEL reinitializing: 0x%x\n", result );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Success.
|
|
result = S_OK;
|
|
cleanup:
|
|
|
|
// Make the server loop quit.
|
|
mine->what_next = quit_wn;
|
|
mine->object_count = 0;
|
|
|
|
// Create a binding handle.
|
|
status = RpcBindingFromStringBinding( GlobalBinding, &handle );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make binding handle form string binding: 0x%x\n" );
|
|
return;
|
|
}
|
|
|
|
// Make a raw RPC call to report the results.
|
|
set_status( handle, result, (unsigned long *) &status );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make RPC call: 0x%x\n", status );
|
|
return;
|
|
}
|
|
local.set_state( dirty_s, THREAD_PRIORITY_NORMAL );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void decrement_object_count()
|
|
{
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
if (InterlockedDecrement( &ProcessAptData.object_count ) == 0)
|
|
wake_up_and_smell_the_roses();
|
|
}
|
|
else
|
|
{
|
|
SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
|
|
if (tls_data != NULL)
|
|
tls_data->object_count -= 1;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL dirty_thread()
|
|
{
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
return ProcessAptData.exit_dirty;
|
|
else
|
|
{
|
|
SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
|
|
return tls_data->exit_dirty;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_cancel()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *obj1 = NULL;
|
|
ITest *obj2 = NULL;
|
|
SAptId id1;
|
|
SAptId id2;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "cancel" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &obj1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = obj1->get_id( &id1 );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &obj2 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = obj2->get_id( &id2 );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Run test between two remote objects.
|
|
success = do_cancel_helper( obj1, id1, obj2, id2 );
|
|
obj1 = NULL;
|
|
obj2 = NULL;
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &obj1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = obj1->get_id( &id1 );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Create in process server.
|
|
result = obj1->get_obj_from_new_apt( &obj2, &id2 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Run test between two local objects.
|
|
success = do_cancel_helper( obj1, id1, obj2, id2 );
|
|
obj1 = NULL;
|
|
obj2 = NULL;
|
|
if (!success)
|
|
goto cleanup;
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (obj1 != NULL)
|
|
obj1->Release();
|
|
if (obj2 != NULL)
|
|
obj2->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nCancel Test Passed.\n" );
|
|
else
|
|
printf( "\n\nCancel Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_cancel_helper( ITest *obj1, SAptId id1, ITest *obj2, SAptId id2 )
|
|
{
|
|
BOOL success = FALSE;
|
|
HRESULT result;
|
|
ITest *helper1 = NULL;
|
|
ITest *helper2 = NULL;
|
|
SAptId hid1;
|
|
SAptId hid2;
|
|
|
|
// Create first helper.
|
|
result = obj1->get_obj_from_new_apt( &helper1, &hid1 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Create second helper.
|
|
result = obj2->get_obj_from_new_apt( &helper2, &hid2 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Register first message filter.
|
|
result = obj1->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Register second message filter.
|
|
result = obj2->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Tell everybody who their neighbor is.
|
|
result = obj1->remember( helper2, hid2 );
|
|
ASSERT( result, "Could not remember object" );
|
|
result = helper2->remember( obj2, id2 );
|
|
ASSERT( result, "Could not remember object" );
|
|
result = obj2->remember( helper1, hid1 );
|
|
ASSERT( result, "Could not remember object" );
|
|
result = helper1->remember( obj1, id1 );
|
|
ASSERT( result, "Could not remember object" );
|
|
|
|
// Cancel one call.
|
|
result = obj1->call_canceled( 1, 1, obj2 );
|
|
ASSERT( result, "Cancel test failed" );
|
|
|
|
// Cancel after recursing.
|
|
result = obj1->call_canceled( 5, 1, obj2 );
|
|
ASSERT( result, "Cancel after recusing failed" );
|
|
|
|
// Make a recursive call and cancel several times.
|
|
result = obj1->call_canceled( 5, 3, obj2 );
|
|
ASSERT( result, "Multiple cancel test failed" );
|
|
|
|
// Tell everybody to forget their neighbor.
|
|
result = obj1->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
result = obj2->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
result = helper1->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
result = helper2->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
|
|
// Release first message filter.
|
|
result = obj1->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not deregister message filter." );
|
|
|
|
// Release second message filter.
|
|
result = obj2->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not deregister message filter." );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (helper1 != NULL)
|
|
helper1->Release();
|
|
if (helper2 != NULL)
|
|
helper2->Release();
|
|
if (obj2 != NULL)
|
|
obj2->Release();
|
|
if (obj1 != NULL)
|
|
obj1->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_crash()
|
|
{
|
|
HRESULT result;
|
|
int i;
|
|
BOOL success = FALSE;
|
|
HANDLE helper[MAX_THREADS];
|
|
DWORD thread_id;
|
|
DWORD status;
|
|
ITest *test = NULL;
|
|
ITest *another = NULL;
|
|
ITest *local = NULL;
|
|
SAptId local_id;
|
|
SAptId test_id;
|
|
SAptId another_id;
|
|
unsigned char c[17];
|
|
WCHAR *binding = NULL;
|
|
/*
|
|
printf( "This test doesn't run. It tests functionallity that is not checked in.\n" );
|
|
return;
|
|
*/
|
|
// Initialize OLE.
|
|
hello( "crash" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
/*
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Recalling Initialize failed" );
|
|
result = initialize(NULL,xxx);
|
|
if (result == S_OK)
|
|
{
|
|
printf( "Recalling Initialize with wrong thread mode succeeded: %x\n", result );
|
|
goto cleanup;
|
|
}
|
|
CoUninitialize();
|
|
CoUninitialize();
|
|
*/
|
|
|
|
// Create a local object.
|
|
local = new CTest;
|
|
ASSERT_EXPR( local != NULL, "Could not create local instance of test server." );
|
|
|
|
// Get a test object.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &test );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Get another test object.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &another );
|
|
ASSERT( result, "Could not create another instance of test server" );
|
|
result = another->get_id( &another_id );
|
|
ASSERT( result, "get_id failed calling second test server" );
|
|
|
|
// Let the server throw and exception and catch it before returning.
|
|
result = test->sick( 95 );
|
|
ASSERT( result, "Internal server fault was not dealt with correctly." );
|
|
|
|
// Throw a non fatal exception on the first call.
|
|
result = test->recurse_excp( local, 0 );
|
|
if (result != RPC_E_SERVERFAULT)
|
|
{
|
|
printf( "Error with top level exception.\n" );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Throw a non fatal exception after recursing.
|
|
result = test->recurse_excp( local, 4 );
|
|
if (result != RPC_E_SERVERFAULT)
|
|
{
|
|
printf( "Error with nested exception.\n" );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Test alignment of the buffer.
|
|
result = test->align( c );
|
|
ASSERT( result, "Alignment call failed" );
|
|
|
|
// Test failure marshalling parameters.
|
|
result = test->pointer( (DWORD *) -1 );
|
|
if (result != STATUS_ACCESS_VIOLATION)
|
|
{
|
|
printf( "Marshalling in parameter failure call failed: 0x%x\n", result );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Test a recursive call.
|
|
result = test->recurse( local, 10 );
|
|
ASSERT( result, "Recursive call failed" );
|
|
|
|
// Test multiple threads.
|
|
Multicall_Test = TRUE;
|
|
for (i = 0; i < MAX_THREADS; i++)
|
|
{
|
|
helper[i] = CreateThread( NULL, 0, thread_helper, test, 0, &thread_id );
|
|
if (helper[i] == NULL)
|
|
{
|
|
printf( "Could not create helper thread number %d.\n", i );
|
|
goto cleanup;
|
|
}
|
|
}
|
|
result = test->sleep(4000);
|
|
ASSERT( result, "Multiple call failed on main thread" );
|
|
status = WaitForMultipleObjects( MAX_THREADS, helper, TRUE, INFINITE );
|
|
if (status == WAIT_FAILED)
|
|
{
|
|
printf( "Could not wait for helper threads to die: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
if (!Multicall_Test)
|
|
{
|
|
printf( "Multiple call failed on helper thread.\n" );
|
|
goto cleanup;
|
|
}
|
|
|
|
// See if methods can correctly call GetMessage.
|
|
another->interrupt( test, another_id, TRUE );
|
|
result = test->recurse_interrupt( local, 10 );
|
|
ASSERT( result, "Recursive call with interrupts failed" );
|
|
another->interrupt( test, another_id, FALSE );
|
|
|
|
// Kill the server on the first call.
|
|
printf( "One of the servers may get a popup now. Hit Ok.\n" );
|
|
result = test->recurse_fatal( local, 0xffffffff, 0, FALSE );
|
|
ASSERT_EXPR( result != S_OK, "Server still alive after top level exception." );
|
|
test->Release();
|
|
test = NULL;
|
|
|
|
// Kill the server after nesting.
|
|
printf( "One of the servers may get a popup now. Hit Ok.\n" );
|
|
result = another->recurse_fatal( local, 0xffffffff, 4, FALSE );
|
|
if (result == S_OK)
|
|
{
|
|
printf( "Server still alive after nested exception.\n" );
|
|
goto cleanup;
|
|
}
|
|
another->Release();
|
|
another = NULL;
|
|
/*
|
|
// Get a test object.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &test );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Register this process to receive raw RPC.
|
|
result = local->register_rpc( TestProtseq, &binding );
|
|
ASSERT( result, "Could not register rpc" );
|
|
|
|
// Tell the server to catch the exception at the message loop.
|
|
result = test->catch_at_top( TRUE, local, binding );
|
|
ASSERT( result, "Could not tell server to catch exception at top" );
|
|
|
|
// Kill the server on the first call.
|
|
result = test->recurse_fatal( local, 0xffffffff, 0, FALSE );
|
|
if (result == S_OK)
|
|
{
|
|
printf( "Server still alive after exception caught at top.\n" );
|
|
goto cleanup;
|
|
}
|
|
test->Release();
|
|
test = NULL;
|
|
|
|
// Check the raw result.
|
|
status = WaitForSingleObject( RawEvent, INFINITE );
|
|
if (status != WAIT_OBJECT_0)
|
|
{
|
|
printf( "Could not wait on RawEvent: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
ASSERT( RawResult, "Problem after exception" );
|
|
|
|
// Get a test object.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &test );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Tell the server to catch the exception at the message loop.
|
|
result = test->catch_at_top( TRUE, local, binding );
|
|
ASSERT( result, "Could not tell server to catch exception at top" );
|
|
|
|
// Kill the server after nesting.
|
|
result = test->recurse_fatal( local, 0xffffffff, 6, FALSE );
|
|
if (result == S_OK)
|
|
{
|
|
printf( "Server still alive after exception caught at top.\n" );
|
|
goto cleanup;
|
|
}
|
|
test->Release();
|
|
test = NULL;
|
|
|
|
// Check the raw result.
|
|
status = WaitForSingleObject( RawEvent, INFINITE );
|
|
if (status != WAIT_OBJECT_0)
|
|
{
|
|
printf( "Could not wait on RawEvent: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
ASSERT( RawResult, "Problem after exception" );
|
|
|
|
// Get a test object.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &test );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Tell the server not to catch the exception at the message loop.
|
|
result = test->catch_at_top( FALSE, local, binding );
|
|
ASSERT( result, "Could not tell server not to catch exception at top" );
|
|
|
|
// Tell the server to catch the exception after nesting, nest some more
|
|
// and then kill it.
|
|
result = test->recurse_fatal( local, 2, 8, FALSE );
|
|
ASSERT( result, "Could not gracefully catch exception" );
|
|
test->Release();
|
|
test = NULL;
|
|
|
|
// Check the raw result.
|
|
status = WaitForSingleObject( RawEvent, INFINITE );
|
|
if (status != WAIT_OBJECT_0)
|
|
{
|
|
printf( "Could not wait on RawEvent: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
ASSERT( RawResult, "Problem after exception" );
|
|
|
|
// Get a test object.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &test );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Tell the server not to catch the exception at the message loop.
|
|
result = test->catch_at_top( FALSE, local, binding );
|
|
ASSERT( result, "Could not tell server not to catch exception at top" );
|
|
|
|
// Get the object ids.
|
|
result = local->get_id( &local_id );
|
|
ASSERT( result, "Could not get local id" );
|
|
result = test->get_id( &test_id );
|
|
ASSERT( result, "Could not get test id" );
|
|
|
|
// Cancel the call to kill the server.
|
|
success = do_crash_helper( local, local_id, test, test_id);
|
|
local = NULL;
|
|
test = NULL;
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
*/
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (test != NULL)
|
|
test->Release();
|
|
if (another != NULL)
|
|
another->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
if (binding != NULL)
|
|
CoTaskMemFree( binding );
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nCrash Test Passed.\n" );
|
|
else
|
|
printf( "\n\nCrash Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_crash_helper( ITest *obj1, SAptId id1, ITest *obj2, SAptId id2 )
|
|
{
|
|
BOOL success = FALSE;
|
|
HRESULT result;
|
|
ITest *helper1 = NULL;
|
|
SAptId hid1;
|
|
RPC_STATUS status;
|
|
|
|
// Create first helper.
|
|
result = obj1->get_obj_from_new_apt( &helper1, &hid1 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Register first message filter.
|
|
result = obj1->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Tell everybody who their neighbor is.
|
|
result = obj2->remember( helper1, hid1 );
|
|
ASSERT( result, "Could not remember object" );
|
|
result = helper1->remember( obj1, id1 );
|
|
ASSERT( result, "Could not remember object" );
|
|
|
|
// Tell the server to catch the exception after nesting, nest some more
|
|
// and then kill it, with cancel.
|
|
result = obj2->recurse_fatal( obj1, 2, 8, TRUE );
|
|
if (result == S_OK)
|
|
ASSERT( result, "Could not gracefully catch exception" );
|
|
obj2->Release();
|
|
obj2 = NULL;
|
|
|
|
// Check the raw result.
|
|
status = WaitForSingleObject( RawEvent, INFINITE );
|
|
if (status != WAIT_OBJECT_0)
|
|
{
|
|
printf( "Could not wait on RawEvent: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
ASSERT( RawResult, "Problem after exception" );
|
|
|
|
// Tell everybody to forget their neighbor.
|
|
result = helper1->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
|
|
// Release first message filter.
|
|
result = obj1->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not deregister message filter." );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (helper1 != NULL)
|
|
helper1->Release();
|
|
if (obj2 != NULL)
|
|
obj2->Release();
|
|
if (obj1 != NULL)
|
|
obj1->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_cstress()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *obj1 = NULL;
|
|
ITest *obj2 = NULL;
|
|
ITest *helper = NULL;
|
|
SAptId id1;
|
|
SAptId id2;
|
|
SAptId hid;
|
|
int i;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "cstress" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &obj1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = obj1->get_id( &id1 );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Create helper.
|
|
result = obj1->get_obj_from_new_apt( &helper, &hid );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &obj2 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = obj2->get_id( &hid );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Register the message filter.
|
|
result = obj1->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Tell everyone to remember their neighbor.
|
|
result = obj1->remember( helper, hid );
|
|
ASSERT( result, "Could not remember object" );
|
|
result = obj2->remember( helper, hid );
|
|
ASSERT( result, "Could not remember object" );
|
|
result = helper->remember( obj1, id1 );
|
|
ASSERT( result, "Could not remember object" );
|
|
|
|
// Loop and cancel a lot of calls.
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
// Cancel remote call.
|
|
result = obj1->cancel_stress( obj2 );
|
|
ASSERT( result, "Remote cancel failed" );
|
|
|
|
// Cancel local call.
|
|
result = obj1->cancel_stress( NULL );
|
|
ASSERT( result, "Local cancel failed" );
|
|
}
|
|
|
|
// Tell everybody to forget their neighbor.
|
|
result = obj1->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
result = obj2->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
result = helper->forget();
|
|
ASSERT( result, "Could not forget neighbor" );
|
|
|
|
// Release the message filter.
|
|
result = obj1->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Create in process server.
|
|
result = obj1->get_obj_from_new_apt( &helper, &hid );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (helper != NULL)
|
|
helper->Release();
|
|
if (obj1 != NULL)
|
|
obj1->Release();
|
|
if (obj2 != NULL)
|
|
obj2->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nCancel Stress Test Passed.\n" );
|
|
else
|
|
printf( "\n\nCancel Stress Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_hook()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
SAptId id;
|
|
ITest *dead = NULL;
|
|
ITest *local = NULL;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "hook" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a remote server.
|
|
result = create_instance( *ServerClsid, &dead, &id );
|
|
ASSERT( result, "Could not create a server" );
|
|
|
|
// Tell it to die.
|
|
result = dead->exit();
|
|
ASSERT( result, "Could not tell server to die" );
|
|
|
|
if (ThreadMode == COINIT_APARTMENTTHREADED)
|
|
{
|
|
// Create a local server.
|
|
result = new_apartment_test( &local, &id, NULL );
|
|
ASSERT( result, "Could not create local server" );
|
|
|
|
// Test hooks in process.
|
|
success = do_hook_helper( TRUE, local, id, dead );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Release the local server.
|
|
local->Release();
|
|
local = NULL;
|
|
dead->Release();
|
|
dead = NULL;
|
|
|
|
// Uninitialize.
|
|
CoUninitialize();
|
|
|
|
// Reinitialize.
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a remote server.
|
|
result = create_instance( *ServerClsid, &dead, &id );
|
|
ASSERT( result, "Could not create a server" );
|
|
|
|
// Tell it to die.
|
|
result = dead->exit();
|
|
ASSERT( result, "Could not tell server to die" );
|
|
}
|
|
|
|
// Create a remote server.
|
|
result = create_instance( *ServerClsid, &server, &id );
|
|
ASSERT( result, "Could not create a server" );
|
|
|
|
// Test remote hooks.
|
|
success = do_hook_helper( FALSE, server, id, dead );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (local != NULL)
|
|
local->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (dead != NULL)
|
|
dead->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nHook Test Passed.\n" );
|
|
else
|
|
printf( "\n\nHook Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_hook_helper( BOOL local, ITest *test, SAptId id, ITest *dead )
|
|
{
|
|
CHook *hook1 = NULL;
|
|
CHook *hook2 = NULL;
|
|
BOOL success = FALSE;
|
|
UUID extent1;
|
|
UUID extent2;
|
|
UUID extent3;
|
|
HRESULT result;
|
|
DWORD i;
|
|
unsigned char *data = NULL;
|
|
|
|
// Call the server.
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Register a hook.
|
|
result = UuidCreate( &extent1 );
|
|
ASSERT_EXPR( result == RPC_S_OK || result == RPC_S_UUID_LOCAL_ONLY,
|
|
"Could not create uuid." );
|
|
hook1 = new CHook( extent1, 1 );
|
|
ASSERT_EXPR( hook1 != NULL, "Could not create new hook." );
|
|
result = CoRegisterChannelHook( extent1, hook1 );
|
|
ASSERT( result, "Could not register first hook" );
|
|
|
|
// Call the server.
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Register the hook in the server
|
|
if (!local)
|
|
{
|
|
result = test->register_hook( extent1, 1 );
|
|
ASSERT( result, "Could not register server hook" );
|
|
}
|
|
|
|
// Call the server.
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Register another hook in the server.
|
|
result = UuidCreate( &extent3 );
|
|
ASSERT_EXPR( result == RPC_S_OK || result == RPC_S_UUID_LOCAL_ONLY,
|
|
"Could not create uuid." );
|
|
result = test->register_hook( extent3, 3 );
|
|
ASSERT( result, "Could not register server hook" );
|
|
|
|
// Call the server.
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Register another hook in the client.
|
|
result = UuidCreate( &extent2 );
|
|
ASSERT_EXPR( result == RPC_S_OK || result == RPC_S_UUID_LOCAL_ONLY,
|
|
"Could not create uuid." );
|
|
hook2 = new CHook( extent2, 2 );
|
|
ASSERT_EXPR( hook2 != NULL, "Could not create new hook." );
|
|
result = CoRegisterChannelHook( extent2, hook2 );
|
|
ASSERT( result, "Could not register first hook" );
|
|
|
|
// Call the server several times.
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not check server" );
|
|
}
|
|
|
|
// Verify the server's hook state.
|
|
if (local)
|
|
result = test->check_hook( 2+NumIterations, 2+NumIterations,
|
|
2+NumIterations, 2+NumIterations,
|
|
0, 0, 0, 0 );
|
|
else
|
|
result = test->check_hook( 0, 0, 4+NumIterations, 4+NumIterations,
|
|
0, 0, 2+NumIterations, 2+NumIterations );
|
|
ASSERT( result, "Could not check server hook" );
|
|
|
|
// Verify the local hook state.
|
|
if (local)
|
|
{
|
|
result = hook1->check( 5+NumIterations, 5+NumIterations,
|
|
5+NumIterations, 5+NumIterations );
|
|
ASSERT( result, "Bad state for hook 1" );
|
|
result = hook2->check( 1+NumIterations, 1+NumIterations,
|
|
1+NumIterations, 1+NumIterations );
|
|
ASSERT( result, "Bad state for hook 2" );
|
|
}
|
|
else
|
|
{
|
|
result = hook1->check( 6+NumIterations, 6+NumIterations, 0, 0 );
|
|
ASSERT( result, "Bad state for hook 1" );
|
|
result = hook2->check( 1+NumIterations, 1+NumIterations, 0, 0 );
|
|
ASSERT( result, "Bad state for hook 2" );
|
|
}
|
|
|
|
// Make a call that fails in get buffer.
|
|
data = (unsigned char *) CoTaskMemAlloc( 1 );
|
|
ASSERT_EXPR( data != NULL, "Could not allocate memory." );
|
|
result = test->get_data( 0x7fffffff, data, 0, &data );
|
|
ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
|
|
|
|
// Make a call that fails in send receive.
|
|
result = dead->check( id );
|
|
ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
|
|
|
|
// Make a call that faults.
|
|
result = test->recurse_excp( NULL, 0 );
|
|
ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
|
|
|
|
// Make a call that fails in the server get buffer.
|
|
result = test->get_data( 0, NULL, 0x7fffffff, &data );
|
|
ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
|
|
|
|
// Make a call that faults in the stub processing out parameters.
|
|
result = test->crash_out( &i );
|
|
ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
|
|
|
|
// Make a successful call.
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// The test succeeded.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (hook1 != NULL)
|
|
hook1->Release();
|
|
if (hook2 != NULL)
|
|
hook2->Release();
|
|
if (data != NULL)
|
|
CoTaskMemFree( data );
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_load_client()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
HRESULT result;
|
|
RPC_BINDING_HANDLE handle = NULL;
|
|
RPC_STATUS status;
|
|
WCHAR binding[MAX_NAME];
|
|
void *buffer = NULL;
|
|
SAptId id;
|
|
SAptId id2;
|
|
HANDLE memory = NULL;
|
|
IStream *stream = NULL;
|
|
LARGE_INTEGER pos;
|
|
DWORD time_null;
|
|
long buf_size;
|
|
DWORD i;
|
|
|
|
// Initialize OLE.
|
|
hello( "Load_Client" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Build binding handle for the server.
|
|
wsprintf( binding, L"%ws:%ws", TestProtseq, Name );
|
|
status = RpcBindingFromStringBinding( binding, &handle );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make binding handle from string binding: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get a marshalled interface from the server over raw RPC.
|
|
get_interface_buffer( handle, &buf_size, (unsigned char **) &buffer, &id,
|
|
(error_status_t *) &status );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not get buffer containing interface: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Allocate memory.
|
|
memory = GlobalAlloc( GMEM_FIXED, buf_size );
|
|
ASSERT_EXPR( memory != NULL, "Could not GlobalAlloc." );
|
|
|
|
// Create a stream.
|
|
result = CreateStreamOnHGlobal( memory, TRUE, &stream );
|
|
ASSERT( result, "Could not create stream" );
|
|
|
|
// Write the data.
|
|
result = stream->Write( buffer, buf_size, NULL );
|
|
ASSERT( result, "Could not write to stream" );
|
|
|
|
// Seek back to the start of the stream.
|
|
pos.QuadPart = 0;
|
|
result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
|
|
ASSERT( result, "Could not seek stream to start" );
|
|
|
|
// Unmarshal Interface.
|
|
result = CoUnmarshalInterface( stream, IID_ITest, (void **) &server );
|
|
ASSERT( result, "Could not unmarshal interface" );
|
|
|
|
// Call once to make sure everything is set up.
|
|
result = server->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
|
|
// Make a lot of null calls.
|
|
time_null = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = server->count();
|
|
ASSERT( result, "Could not make count call" );
|
|
}
|
|
time_null = GetTickCount() - time_null;
|
|
|
|
// Notify the server that we are done.
|
|
release_interface( handle, (error_status_t *) &status );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not release interface: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Print the results.
|
|
printf( "%d uS / DCOM Null Call\n", time_null*1000/NumIterations );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (handle != NULL)
|
|
RpcBindingFree( &handle );
|
|
if (buffer != NULL)
|
|
midl_user_free( buffer );
|
|
if (stream != NULL)
|
|
stream->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nLoad_Client Test Passed.\n" );
|
|
else
|
|
printf( "\n\nLoad_Client Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_load_server()
|
|
{
|
|
BOOL success = FALSE;
|
|
SAptId id;
|
|
HRESULT result;
|
|
RPC_STATUS status;
|
|
RPC_BINDING_VECTOR *bindings = NULL;
|
|
HANDLE thread = NULL;
|
|
DWORD thread_id;
|
|
|
|
// Initialize OLE.
|
|
hello( "Load_Server" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Start the status thread.
|
|
thread = CreateThread( NULL, 0, status_helper, NULL, 0, &thread_id );
|
|
ASSERT_EXPR( thread != 0, "Could not create thread." );
|
|
|
|
// Set up thread switching.
|
|
GlobalThreadId = GetCurrentThreadId();
|
|
|
|
// Create a local server
|
|
GlobalTest = new CTest;
|
|
ASSERT( !GlobalTest, "Could not create local server" );
|
|
|
|
// Register a protseq.
|
|
status = RpcServerUseProtseq( TestProtseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
|
NULL );
|
|
ASSERT( status, "Could not register protseq" );
|
|
|
|
// Register the dog interface.
|
|
status = RpcServerRegisterIf(xIDog_v0_1_s_ifspec,
|
|
NULL, // MgrTypeUuid
|
|
NULL); // MgrEpv; null means use default
|
|
ASSERT( status, "Could not register RPC interface" );
|
|
|
|
// Inquire the endpoints.
|
|
status = RpcServerInqBindings(&bindings);
|
|
ASSERT( status, "Could not inquire bindings" );
|
|
|
|
// Register them in the endpoint mapper.
|
|
status = RpcEpRegister( xIDog_v0_1_s_ifspec, bindings, NULL, NULL );
|
|
ASSERT( status, "Could not register with endpoint mapper" );
|
|
|
|
// Start RPC listening.
|
|
status = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE );
|
|
ASSERT( status, "Could not start RPC listening" );
|
|
|
|
// Wait until the objects are released.
|
|
server_loop();
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (thread != NULL)
|
|
CloseHandle( thread );
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nLoad_Server Test Passed.\n" );
|
|
else
|
|
printf( "\n\nLoad_Server Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_lots()
|
|
{
|
|
do_cancel();
|
|
do_crash();
|
|
do_null();
|
|
do_ring();
|
|
do_rundown();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_mmarshal()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
ITest *client2 = NULL;
|
|
ITest *test = NULL;
|
|
ITest *callee = NULL;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "mmarshal" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client2 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &test );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &callee );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Tell the first client to start calling the test object.
|
|
result = client1->interrupt_marshal( test, callee);
|
|
ASSERT( result, "Could not start client" );
|
|
|
|
// Tell the first client to start calling the test object.
|
|
result = client2->interrupt_marshal( test, callee);
|
|
ASSERT( result, "Could not start client" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (client2 != NULL)
|
|
client2->Release();
|
|
if (test != NULL)
|
|
test->Release();
|
|
if (callee != NULL)
|
|
callee->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nMultiple marshal Test passed if all server processes exit.\n" );
|
|
else
|
|
printf( "\n\nMultiple marshal Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_null()
|
|
{
|
|
HRESULT result;
|
|
BOOL success = FALSE;
|
|
ITest *test = NULL;
|
|
SAptId id;
|
|
|
|
// Initialize OLE.
|
|
hello( "null" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Get a test object on another apartment.
|
|
result = new_apartment_test( &test, &id, NULL );
|
|
ASSERT( result, "Could not create apartment instance of test server" );
|
|
|
|
// Call the test object.
|
|
result = test->check( id );
|
|
ASSERT( result, "Could not call check in another apartment" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (test != NULL)
|
|
test->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nNull Test Passed.\n" );
|
|
else
|
|
printf( "\n\nNull Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_one()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
ITest *server2 = NULL;
|
|
ITest *local = NULL;
|
|
ITest *local2 = NULL;
|
|
SAptId id_server;
|
|
SAptId id_server2;
|
|
SAptId id_local;
|
|
SAptId id_local2;
|
|
HRESULT result;
|
|
DWORD i;
|
|
|
|
// Initialize OLE.
|
|
hello( "one" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a possibly remote object.
|
|
result = create_instance( *ServerClsid, &server, &id_server );
|
|
ASSERT( result, "Could not create server" );
|
|
|
|
// Test delegation
|
|
if (ThreadMode != COINIT_MULTITHREADED)
|
|
{
|
|
// Create a local server
|
|
result = new_apartment_test( &local, &id_local, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
// Create a local server
|
|
result = new_apartment_test( &local2, &id_local2, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
success = do_security_delegate( local, id_local, local2, id_local2 );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
}
|
|
|
|
// Create a client possibly on a remote machine.
|
|
result = create_instance( *ServerClsid, &server2, &id_server2 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server2 != NULL, "Create instance returned NULL." );
|
|
|
|
// Test delegation
|
|
success = do_security_delegate( server, id_server, server2, id_server2 );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Set security.
|
|
result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket" );
|
|
|
|
// Verify the authentication information.
|
|
DWORD authn_svc_out, authz_svc_out, authn_level_out, imp_level_out;
|
|
WCHAR *princ_name_out;
|
|
result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
|
|
&princ_name_out, &authn_level_out,
|
|
&imp_level_out, NULL, NULL );
|
|
if (result == S_OK)
|
|
{
|
|
ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
|
|
ASSERT_EXPR( RPC_C_AUTHN_LEVEL_PKT_PRIVACY <= authn_level_out, "Wrong authentication level." );
|
|
ASSERT_EXPR( RPC_C_IMP_LEVEL_IMPERSONATE == imp_level_out, "Wrong impersonation level." );
|
|
ASSERT_EXPR( RPC_C_AUTHN_WINNT == authn_svc_out, "Wrong authentication service." );
|
|
ASSERT_EXPR( RPC_C_AUTHZ_NONE == authz_svc_out, "Wrong authorization service." );
|
|
}
|
|
|
|
// Call it.
|
|
result = server->check( id_server );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Set security.
|
|
result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket" );
|
|
|
|
// Call it.
|
|
result = server->check( id_server );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Test nested impersonation for a remote object.
|
|
success = do_security_nested( server, id_server );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
if (local2 != NULL)
|
|
local2->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nOne Test Passed.\n" );
|
|
else
|
|
printf( "\n\nOne Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_perf()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
ITest *client2 = NULL;
|
|
ITest *tmp = NULL;
|
|
CTest *local = NULL;
|
|
SAptId id;
|
|
HRESULT result;
|
|
DWORD time_remote = -1;
|
|
DWORD time_local = -1;
|
|
DWORD time_in = -1;
|
|
DWORD time_out = -1;
|
|
DWORD time_lin = -1;
|
|
DWORD time_lout = -1;
|
|
int i;
|
|
|
|
// Initialize OLE.
|
|
hello( "perf" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
/**/
|
|
// Call once to make sure everything is set up.
|
|
result = client1->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
|
|
// Call a lot of times.
|
|
time_remote = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client1->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
}
|
|
time_remote = GetTickCount() - time_remote;
|
|
/**/
|
|
// Create a local client
|
|
result = new_apartment_test( &client2, &id, NULL );
|
|
ASSERT( result, "Could not create local client" );
|
|
/**/
|
|
// Call once to make sure everything is set up.
|
|
result = client2->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
|
|
// Call a lot of times.
|
|
time_local = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client2->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
}
|
|
time_local = GetTickCount() - time_local;
|
|
/**/
|
|
// Create a local object.
|
|
local = new CTest;
|
|
ASSERT_EXPR( local != NULL, "Could not create local object" );
|
|
/**/
|
|
// Pass it to the server once.
|
|
result = client1->interface_in( local );
|
|
ASSERT( result, "Could not pass in interface" );
|
|
|
|
// Pass it to the server a lot of times.
|
|
time_in = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client1->interface_in( local );
|
|
ASSERT( result, "Could not pass in interface" );
|
|
}
|
|
time_in = GetTickCount() - time_in;
|
|
|
|
// Create another remote object.
|
|
result = client1->get_obj_from_this_apt( &tmp, &id );
|
|
ASSERT( result, "Could not get new object." );
|
|
|
|
// Have the server remember it.
|
|
result = client1->remember( tmp, id );
|
|
ASSERT( result, "Could not remember object" );
|
|
tmp->Release();
|
|
tmp = NULL;
|
|
|
|
// Get and release the remote object a lot of times.
|
|
time_out = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client1->get_next( &tmp, &id );
|
|
ASSERT( result, "Could not pass out interface" );
|
|
tmp->Release();
|
|
tmp = NULL;
|
|
}
|
|
time_out = GetTickCount() - time_out;
|
|
client1->forget();
|
|
/**/
|
|
// Pass the object from this thread to another thread once.
|
|
result = client2->interface_in( local );
|
|
ASSERT( result, "Could not pass in interface" );
|
|
|
|
// Pass the object from this thread to another thread.
|
|
time_lin = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client2->interface_in( local );
|
|
ASSERT( result, "Could not pass in interface" );
|
|
}
|
|
time_lin = GetTickCount() - time_lin;
|
|
/**/
|
|
// Create another remote object.
|
|
result = client2->get_obj_from_this_apt( &tmp, &id );
|
|
ASSERT( result, "Could not get new object." );
|
|
|
|
// Have the server remember it.
|
|
result = client2->remember( tmp, id );
|
|
ASSERT( result, "Could not remember object" );
|
|
tmp->Release();
|
|
tmp = NULL;
|
|
|
|
// Get and release the remote object a lot of times.
|
|
time_lout = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client2->get_next( &tmp, &id );
|
|
ASSERT( result, "Could not pass out interface" );
|
|
tmp->Release();
|
|
tmp = NULL;
|
|
}
|
|
time_lout = GetTickCount() - time_lout;
|
|
client2->forget();
|
|
/**/
|
|
// Print the results.
|
|
printf( "%d uS / Local Call\n", time_local*1000/NumIterations );
|
|
printf( "%d uS / Remote Call\n", time_remote*1000/NumIterations );
|
|
printf( "%d uS / Interface In Call\n", time_in*1000/NumIterations );
|
|
printf( "%d uS / Interface Out Call\n", time_out*1000/NumIterations );
|
|
printf( "%d uS / Local Interface In Call\n", time_lin*1000/NumIterations );
|
|
printf( "%d uS / Local Interface Out Call\n", time_lout*1000/NumIterations );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (tmp != NULL)
|
|
tmp->Release();
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (client2 != NULL)
|
|
client2->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nPerf Test Passed.\n" );
|
|
else
|
|
printf( "\n\nPerf Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_perfremote()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
SAptId id;
|
|
HRESULT result;
|
|
DWORD time_remote;
|
|
int i;
|
|
|
|
// Initialize OLE.
|
|
hello( "Perf Remote" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Call once to make sure everything is set up.
|
|
result = client1->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
|
|
// Call a lot of times.
|
|
time_remote = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = client1->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
}
|
|
time_remote = GetTickCount() - time_remote;
|
|
|
|
// Print the results.
|
|
printf( "%d uS / Remote Call\n", time_remote*1000/NumIterations );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nPerf Test Passed.\n" );
|
|
else
|
|
printf( "\n\nPerf Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_perfrpc()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
SAptId id;
|
|
HRESULT result;
|
|
int i;
|
|
WCHAR *binding = NULL;
|
|
RPC_BINDING_HANDLE handle = NULL;
|
|
RPC_BINDING_HANDLE copy = NULL;
|
|
RPC_BINDING_HANDLE object = NULL;
|
|
RPC_STATUS status;
|
|
DWORD time_remote;
|
|
DWORD time_integrity;
|
|
DWORD time_copy;
|
|
DWORD time_copy_secure;
|
|
DWORD time_object;
|
|
UUID object_id;
|
|
|
|
// Initialize OLE.
|
|
hello( "Perf RPC" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = create_instance( *ServerClsid, &client1, &id );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Ask the server to register rpc.
|
|
result = client1->register_rpc( TestProtseq, &binding );
|
|
ASSERT( result, "Could not register rpc interface" );
|
|
|
|
// Create a binding handle.
|
|
status = RpcBindingFromStringBinding( binding, &handle );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make binding handle form string binding: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get a binding handle for the object id test.
|
|
status = RpcBindingCopy( handle, &object );
|
|
ASSERT( status, "Could not copy binding" );
|
|
|
|
// Copy the binding handle once.
|
|
status = RpcBindingCopy( handle, © );
|
|
ASSERT( status, "Could not copy binding" );
|
|
RpcBindingFree( © );
|
|
copy = NULL;
|
|
|
|
// Time copying the binding handle.
|
|
time_copy = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
status = RpcBindingCopy( handle, © );
|
|
ASSERT( status, "Could not copy binding" );
|
|
RpcBindingFree( © );
|
|
copy = NULL;
|
|
}
|
|
time_copy = GetTickCount() - time_copy;
|
|
|
|
// Make a raw rpc call to make sure everything is set up.
|
|
nullcall( handle );
|
|
|
|
// Call a lot of times.
|
|
time_remote = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
nullcall( handle );
|
|
}
|
|
time_remote = GetTickCount() - time_remote;
|
|
|
|
// Set the object id.
|
|
result = RpcBindingSetObject( object, &object_id );
|
|
ASSERT( result, "Could not set object id" );
|
|
|
|
// Make a raw rpc call to make sure everything is set up.
|
|
nullcall( object );
|
|
|
|
// Call a lot of times.
|
|
time_object = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
nullcall( object );
|
|
}
|
|
time_object = GetTickCount() - time_object;
|
|
|
|
// Add security.
|
|
status = RpcBindingSetAuthInfo( handle, L"none", RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
|
|
RPC_C_AUTHN_WINNT, NULL, 0 );
|
|
ASSERT( status, "Could not set auth info" );
|
|
|
|
// Copy the binding handle once.
|
|
status = RpcBindingCopy( handle, © );
|
|
ASSERT( status, "Could not copy binding" );
|
|
RpcBindingFree( © );
|
|
copy = NULL;
|
|
|
|
// Time copying the binding handle.
|
|
time_copy_secure = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
status = RpcBindingCopy( handle, © );
|
|
ASSERT( status, "Could not copy binding" );
|
|
RpcBindingFree( © );
|
|
copy = NULL;
|
|
}
|
|
time_copy_secure = GetTickCount() - time_copy_secure;
|
|
|
|
// Make a raw rpc call to make sure everything is set up.
|
|
nullcall( handle );
|
|
|
|
// Call a lot of times.
|
|
time_integrity = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
nullcall( handle );
|
|
}
|
|
time_integrity = GetTickCount() - time_integrity;
|
|
|
|
// Print the results.
|
|
printf( "%d uS / Raw RPC Remote Call\n", time_remote*1000/NumIterations );
|
|
printf( "%d uS / Raw Integrity RPC Remote Call\n", time_integrity*1000/NumIterations );
|
|
printf( "%d uS / Raw RPC with OID Remote Call\n", time_object*1000/NumIterations );
|
|
printf( "%d uS / handle copy\n", time_copy*1000/NumIterations );
|
|
printf( "%d uS / secure handle copy\n", time_copy_secure*1000/NumIterations );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (binding != NULL)
|
|
CoTaskMemFree( binding );
|
|
if (copy != NULL)
|
|
RpcBindingFree( © );
|
|
if (object != NULL)
|
|
RpcBindingFree( &object );
|
|
if (handle != NULL)
|
|
RpcBindingFree( &handle );
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nPerf Test Passed.\n" );
|
|
else
|
|
printf( "\n\nPerf Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_perfsec()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
ITest *copy = NULL;
|
|
SAptId id;
|
|
HRESULT result;
|
|
WCHAR *binding = NULL;
|
|
//DWORD time_null;
|
|
DWORD time_impersonate;
|
|
DWORD time_acl;
|
|
DWORD time_audit;
|
|
DWORD i;
|
|
DWORD j;
|
|
RPC_BINDING_HANDLE handle = NULL;
|
|
RPC_STATUS status;
|
|
TOKEN_USER *token_info = NULL;
|
|
DWORD info_size = 1024;
|
|
HANDLE token = NULL;
|
|
PSID pSID = NULL;
|
|
DWORD level[4];
|
|
DWORD time_rpc[4];
|
|
DWORD time_null[4];
|
|
DWORD time_ifin[4];
|
|
DWORD time_ifout[4];
|
|
CTest local;
|
|
ITest *server2 = NULL;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER nothing;
|
|
LARGE_INTEGER init_sec_none;
|
|
LARGE_INTEGER init_sec_con;
|
|
LARGE_INTEGER reg_sec;
|
|
LARGE_INTEGER query_proxy;
|
|
LARGE_INTEGER set_proxy;
|
|
LARGE_INTEGER copy_proxy;
|
|
LARGE_INTEGER freq;
|
|
DWORD get_call;
|
|
DWORD query_client;
|
|
DWORD impersonate;
|
|
DWORD revert;
|
|
DWORD authn_svc;
|
|
DWORD authz_svc;
|
|
DWORD authn_level;
|
|
DWORD imp_level;
|
|
DWORD capabilities;
|
|
WCHAR *principal = NULL;
|
|
SOLE_AUTHENTICATION_SERVICE svc_list;
|
|
|
|
// Initialize OLE.
|
|
hello( "perfsec" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Import the security APIs.
|
|
GCoCopyProxy = (CoCopyProxyFn) Fixup( "CoCopyProxy" );
|
|
GCoInitializeSecurity = (CoInitializeSecurityFn) Fixup( "CoInitializeSecurity" );
|
|
GCoQueryProxyBlanket = (CoQueryProxyBlanketFn) Fixup( "CoQueryProxyBlanket" );
|
|
GCoSetProxyBlanket = (CoSetProxyBlanketFn) Fixup( "CoSetProxyBlanket" );
|
|
if (GCoCopyProxy == NULL ||
|
|
GCoInitializeSecurity == NULL ||
|
|
GCoQueryProxyBlanket == NULL ||
|
|
GCoSetProxyBlanket == NULL)
|
|
goto cleanup;
|
|
|
|
// Measure the performance of nothing.
|
|
QueryPerformanceFrequency( &freq );
|
|
QueryPerformanceCounter( &start );
|
|
QueryPerformanceCounter( ¬hing );
|
|
nothing.QuadPart = 1000000 * (nothing.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
|
|
// Measure the performance of initialize.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
QueryPerformanceCounter( &init_sec_none );
|
|
init_sec_none.QuadPart = 1000000 * (init_sec_none.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not initialize security" );
|
|
|
|
// Reinitialize.
|
|
CoUninitialize();
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Reinitialize failed" );
|
|
|
|
// Measure the performance of initialize.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
QueryPerformanceCounter( &init_sec_con );
|
|
init_sec_con.QuadPart = 1000000 * (init_sec_con.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not initialize security at connect" );
|
|
|
|
// Reinitialize.
|
|
CoUninitialize();
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Reinitialize failed" );
|
|
|
|
// Measure the performance of register.
|
|
svc_list.dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
svc_list.dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
svc_list.pPrincipalName = NULL;
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoInitializeSecurity( NULL, 1, &svc_list, NULL,
|
|
RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
QueryPerformanceCounter( ®_sec );
|
|
reg_sec.QuadPart = 1000000 * (reg_sec.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not initialize security with authentication services" );
|
|
|
|
// Create a client.
|
|
result = create_instance( *ServerClsid, &server, &id );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Measure the performance of set proxy.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, RPC_C_AUTHN_LEVEL_CONNECT, 0, NULL, 0 );
|
|
QueryPerformanceCounter( &set_proxy );
|
|
set_proxy.QuadPart = 1000000 * (set_proxy.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not set proxy" );
|
|
|
|
// Measure the performance of query proxy
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoQueryProxyBlanket( server, &authn_svc, &authz_svc, &principal,
|
|
&authn_level, &imp_level, NULL, &capabilities );
|
|
QueryPerformanceCounter( &query_proxy );
|
|
query_proxy.QuadPart = 1000000 * (query_proxy.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not query_proxy" );
|
|
|
|
// Measure the performance of copy proxy.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoCopyProxy( server, (IUnknown **) © );
|
|
QueryPerformanceCounter( ©_proxy );
|
|
copy_proxy.QuadPart = 1000000 * (copy_proxy.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not copy proxy" );
|
|
|
|
// Make a call to measure the performance of the server side APIs.
|
|
result = server->security_performance( &get_call, &query_client, &impersonate,
|
|
&revert );
|
|
ASSERT( result, "Could not get server API performance" );
|
|
|
|
// Ask the server to register rpc.
|
|
result = server->register_rpc( TestProtseq, &binding );
|
|
ASSERT( result, "Could not register rpc interface" );
|
|
|
|
// Create a binding handle.
|
|
status = RpcBindingFromStringBinding( binding, &handle );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make binding handle from string binding: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Create another remote object.
|
|
result = server->get_obj_from_this_apt( &server2, &id );
|
|
ASSERT( result, "Could not get new object." );
|
|
|
|
// Have the server remember it.
|
|
result = server->remember( server2, id );
|
|
ASSERT( result, "Could not remember object" );
|
|
server2->Release();
|
|
server2 = NULL;
|
|
|
|
// Try several security levels.
|
|
level[0] = RPC_C_AUTHN_LEVEL_NONE;
|
|
level[1] = RPC_C_AUTHN_LEVEL_CONNECT;
|
|
level[2] = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
|
|
level[3] = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
// Set security on the RPC binding handle.
|
|
result = RpcBindingSetAuthInfo( handle, NULL, level[j], RPC_C_AUTHN_WINNT,
|
|
NULL, RPC_C_AUTHZ_NONE );
|
|
ASSERT( result, "Could not set rpc auth info" );
|
|
|
|
// Set security on the proxy.
|
|
result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, level[j], RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL, EOAC_NONE );
|
|
ASSERT( result, "Could not set DCOM auth info" );
|
|
|
|
// Make a raw rpc call to make sure everything is set up.
|
|
nullcall( handle );
|
|
|
|
// Make some raw rpc calls.
|
|
time_rpc[j] = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
nullcall( handle );
|
|
}
|
|
time_rpc[j] = GetTickCount() - time_rpc[j];
|
|
|
|
// Make a null dcom call to make sure everything is set up.
|
|
result = server->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
|
|
// Put up a popup about the test starting.
|
|
if (Popup)
|
|
MessageBox( NULL, L"Now would be a good time to start ICECAP.",
|
|
L"Not Me", MB_YESNO | MB_ICONEXCLAMATION );
|
|
|
|
// Make some null calls.
|
|
time_null[j] = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = server->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
}
|
|
time_null[j] = GetTickCount() - time_null[j];
|
|
|
|
// Put up a popup about the test stopping.
|
|
if (Popup)
|
|
MessageBox( NULL, L"Now would be a good time to stop ICECAP.",
|
|
L"Not Me", MB_YESNO | MB_ICONSTOP );
|
|
|
|
// Pass an interface in to set everything up.
|
|
result = server->interface_in( &local );
|
|
ASSERT( result, "Could not make interface_in call" );
|
|
|
|
// Make some interface in calls.
|
|
time_ifin[j] = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = server->interface_in( &local );
|
|
ASSERT( result, "Could not make interface_in call" );
|
|
}
|
|
time_ifin[j] = GetTickCount() - time_ifin[j];
|
|
|
|
// Pass an interface out to set everything up.
|
|
result = server->get_next( &server2, &id );
|
|
ASSERT( result, "Could not make interface out call" );
|
|
server2->Release();
|
|
server2 = NULL;
|
|
|
|
// Make some interface_out calls.
|
|
time_ifout[j] = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = server->get_next( &server2, &id );
|
|
ASSERT( result, "Could not make interface out call" );
|
|
server2->Release();
|
|
server2 = NULL;
|
|
}
|
|
time_ifout[j] = GetTickCount() - time_ifout[j];
|
|
}
|
|
|
|
// Release the second remote object.
|
|
result = server->forget();
|
|
ASSERT( result, "Could not forget" );
|
|
|
|
// Print the DCOM call results.
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
printf( "% 8d uS / Raw RPC Remote Call at level %d\n",
|
|
time_rpc[j]*1000/NumIterations, level[j] );
|
|
printf( "% 8d uS / Null Remote Call at level %d\n",
|
|
time_null[j]*1000/NumIterations, level[j] );
|
|
printf( "% 8d uS / Interface in Remote Call at level %d\n",
|
|
time_ifin[j]*1000/NumIterations, level[j] );
|
|
printf( "% 8d uS / Interface out Remote Call at level %d\n",
|
|
time_ifout[j]*1000/NumIterations, level[j] );
|
|
}
|
|
|
|
// Print the API call results.
|
|
printf( "nothing took %duS\n", nothing.u.LowPart );
|
|
printf( "CoInitializeSecurity at none took %duS\n", init_sec_none.u.LowPart );
|
|
printf( "CoInitializeSecurity at connect took %duS\n", init_sec_con.u.LowPart );
|
|
printf( "CoInitializeSecurity with service took %duS\n", reg_sec.u.LowPart );
|
|
printf( "CoQueryProxyBlanket took %duS\n", query_proxy.u.LowPart );
|
|
printf( "CoSetProxyBlanket took %duS\n", set_proxy.u.LowPart );
|
|
printf( "CoCopyProxy took %duS\n", copy_proxy.u.LowPart );
|
|
printf( "CoGetCallContext took %duS\n", get_call );
|
|
printf( "CoQueryClientBlanket took %duS\n", query_client );
|
|
printf( "CoImpersonateClient took %duS\n", impersonate );
|
|
printf( "CoRevertToSelf took %duS\n", revert );
|
|
|
|
/*
|
|
// Open the process's token.
|
|
OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token );
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not OpenProcessToken" );
|
|
|
|
// Lookup SID of process token.
|
|
token_info = (TOKEN_USER *) malloc( info_size );
|
|
GetTokenInformation( token, TokenUser, token_info, info_size, &info_size );
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
pSID = token_info->User.Sid;
|
|
|
|
// Ask the server to make an ACL.
|
|
result = server->make_acl( (HACKSID *) pSID );
|
|
ASSERT( result, "Could not make ACL" );
|
|
|
|
// Make a raw rpc call to make sure everything is set up.
|
|
nullcall( handle );
|
|
|
|
// Call a lot of times.
|
|
time_null = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
nullcall( handle );
|
|
}
|
|
time_null = GetTickCount() - time_null;
|
|
|
|
// Call a lot of times.
|
|
time_impersonate = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = impersonate_call( handle );
|
|
ASSERT( result, "Could not make impersonate call" );
|
|
}
|
|
time_impersonate = GetTickCount() - time_impersonate;
|
|
|
|
// Call a lot of times.
|
|
time_acl = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = acl_call( handle );
|
|
ASSERT( result, "Could not make acl call" );
|
|
}
|
|
time_acl = GetTickCount() - time_acl;
|
|
|
|
// Call a lot of times.
|
|
time_audit = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = audit_call( handle );
|
|
ASSERT( result, "Could not make audit call" );
|
|
}
|
|
time_audit = GetTickCount() - time_audit;
|
|
|
|
// Print the results.
|
|
printf( "%d uS / Raw RPC Remote Call\n", time_null*1000/NumIterations );
|
|
printf( "%d uS / Raw Impersonate RPC Remote Call\n", time_impersonate*1000/NumIterations );
|
|
printf( "%d uS / Raw ACL RPC Remote Call\n", time_acl*1000/NumIterations );
|
|
printf( "%d uS / Raw audit RPC Remote Call\n", time_audit*1000/NumIterations );
|
|
*/
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (principal != NULL)
|
|
CoTaskMemFree( principal );
|
|
if (copy != NULL)
|
|
copy->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (binding != NULL)
|
|
CoTaskMemFree( binding );
|
|
if (handle != NULL)
|
|
RpcBindingFree( &handle );
|
|
if (token_info != NULL)
|
|
free( token_info );
|
|
if (token != NULL)
|
|
CloseHandle( token );
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nSec Test Passed.\n" );
|
|
else
|
|
printf( "\n\nSec Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_post()
|
|
{
|
|
BOOL success = FALSE;
|
|
|
|
// Say hello.
|
|
printf( "Posting a message to window 0x%x\n", NumIterations );
|
|
success = PostMessageA( (HWND) NumIterations, WM_USER, 0, 0 );
|
|
|
|
if (success)
|
|
printf( "\n\nPostMessageA succeeded.\n" );
|
|
else
|
|
printf( "\n\nPostMessageA failed: 0x%x\n", GetLastError() );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_reject()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
ITest *client2 = NULL;
|
|
SAptId id1;
|
|
SAptId id2;
|
|
IAdviseSink *advise1 = NULL;
|
|
IAdviseSink *advise2 = NULL;
|
|
HRESULT result;
|
|
CTest *local = NULL;
|
|
|
|
// Initialize OLE.
|
|
hello( "reject" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a local object.
|
|
local = new CTest;
|
|
ASSERT_EXPR( local != NULL, "Could not create local instance of test server." );
|
|
|
|
// Create a server
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = client1->get_id( &id1 );
|
|
ASSERT( result, "Could not get id of server" );
|
|
|
|
// Register the local message filter.
|
|
result = local->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Register the remote message filter.
|
|
result = client1->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Make the server reject the next call.
|
|
result = client1->reject_next();
|
|
ASSERT( result, "Could not reject next call" );
|
|
|
|
// Make us retry the next rejected call.
|
|
result = local->retry_next();
|
|
ASSERT( result, "Could not retry next call" );
|
|
|
|
// Call check.
|
|
result = client1->check( id1 );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Create a local server.
|
|
result = local->get_obj_from_new_apt( &client2, &id2 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Register the remote message filter.
|
|
result = client2->register_message_filter( TRUE );
|
|
ASSERT( result, "Could not register message filter." );
|
|
|
|
// Make the server reject the next call.
|
|
result = client2->reject_next();
|
|
ASSERT( result, "Could not reject next call" );
|
|
|
|
// Make us retry the next rejected call.
|
|
result = local->retry_next();
|
|
ASSERT( result, "Could not retry next call" );
|
|
|
|
// Call check.
|
|
result = client2->check( id2 );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Release the message filters.
|
|
result = local->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not deregister message filter." );
|
|
result = client1->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not deregister message filter." );
|
|
result = client2->register_message_filter( FALSE );
|
|
ASSERT( result, "Could not deregister message filter." );
|
|
|
|
// Create an advise object on another process
|
|
result = client1->get_advise( &advise1 );
|
|
ASSERT( result, "Could not get advise: 0x%x" );
|
|
|
|
// Make an async call.
|
|
advise1->OnSave();
|
|
|
|
// Create an advise object on another thread
|
|
result = client2->get_advise( &advise2 );
|
|
ASSERT( result, "Could not get advise: 0x%x" );
|
|
|
|
// Make an async call.
|
|
advise2->OnSave();
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (advise2 != NULL)
|
|
advise2->Release();
|
|
if (advise1 != NULL)
|
|
advise1->Release();
|
|
if (client2 != NULL)
|
|
client2->Release();
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nReject Test Passed.\n" );
|
|
else
|
|
printf( "\n\nReject Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_remote_client()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
ITest *server2 = NULL;
|
|
HRESULT result;
|
|
RPC_BINDING_HANDLE handle = NULL;
|
|
RPC_STATUS status;
|
|
WCHAR binding[MAX_NAME];
|
|
void *buffer = NULL;
|
|
SAptId id;
|
|
SAptId id2;
|
|
HANDLE memory = NULL;
|
|
IStream *stream = NULL;
|
|
LARGE_INTEGER pos;
|
|
DWORD time_rpc;
|
|
DWORD time_null;
|
|
DWORD time_marshal;
|
|
long buf_size;
|
|
DWORD i;
|
|
|
|
// Initialize OLE.
|
|
hello( "RemoteClient" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Build binding handle for the server.
|
|
wsprintf( binding, L"%ws:%ws", TestProtseq, Name );
|
|
status = RpcBindingFromStringBinding( binding, &handle );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make binding handle from string binding: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get a marshalled interface from the server over raw RPC.
|
|
get_interface_buffer( handle, &buf_size, (unsigned char **) &buffer, &id,
|
|
(error_status_t *) &status );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not get buffer containing interface: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Allocate memory.
|
|
memory = GlobalAlloc( GMEM_FIXED, buf_size );
|
|
ASSERT_EXPR( memory != NULL, "Could not GlobalAlloc." );
|
|
|
|
// Create a stream.
|
|
result = CreateStreamOnHGlobal( memory, TRUE, &stream );
|
|
ASSERT( result, "Could not create stream" );
|
|
|
|
// Write the data.
|
|
result = stream->Write( buffer, buf_size, NULL );
|
|
ASSERT( result, "Could not write to stream" );
|
|
|
|
// Seek back to the start of the stream.
|
|
pos.QuadPart = 0;
|
|
result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
|
|
ASSERT( result, "Could not seek stream to start" );
|
|
|
|
// Unmarshal Interface.
|
|
result = CoUnmarshalInterface( stream, IID_ITest, (void **) &server );
|
|
ASSERT( result, "Could not unmarshal interface" );
|
|
|
|
// Call once to make sure everything is set up.
|
|
result = server->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
|
|
// Make a lot of null calls.
|
|
time_null = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = server->null();
|
|
ASSERT( result, "Could not make null call" );
|
|
}
|
|
time_null = GetTickCount() - time_null;
|
|
|
|
// Make a lot of marshalling calls.
|
|
time_marshal = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = server->get_obj_from_this_apt( &server2, &id2);
|
|
ASSERT( result, "Could not make marshal call" );
|
|
server2->Release();
|
|
server2 = NULL;
|
|
}
|
|
time_marshal = GetTickCount() - time_marshal;
|
|
|
|
// Make a lot of RPC calls
|
|
nullcall( handle );
|
|
time_rpc = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
nullcall( handle );
|
|
}
|
|
time_rpc = GetTickCount() - time_rpc;
|
|
|
|
// Print the results.
|
|
printf( "%d uS / RPC Null Call\n", time_rpc*1000/NumIterations );
|
|
printf( "%d uS / DCOM Null Call\n", time_null*1000/NumIterations );
|
|
printf( "%d uS / DCOM Marshal Call\n", time_marshal*1000/NumIterations );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (handle != NULL)
|
|
RpcBindingFree( &handle );
|
|
if (buffer != NULL)
|
|
midl_user_free( buffer );
|
|
if (stream != NULL)
|
|
stream->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nRemoteClient Test Passed.\n" );
|
|
else
|
|
printf( "\n\nRemoteClient Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_remote_server()
|
|
{
|
|
BOOL success = FALSE;
|
|
SAptId id;
|
|
HRESULT result;
|
|
RPC_STATUS status;
|
|
RPC_BINDING_VECTOR *bindings = NULL;
|
|
|
|
// Initialize OLE.
|
|
hello( "RemoteServer" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Set up thread switching.
|
|
GlobalThreadId = GetCurrentThreadId();
|
|
|
|
// Create a local server
|
|
GlobalTest = new CTest;
|
|
ASSERT( !GlobalTest, "Could not create local server" );
|
|
|
|
// Register a protseq.
|
|
status = RpcServerUseProtseq( TestProtseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
|
NULL );
|
|
ASSERT( status, "Could not register protseq" );
|
|
|
|
// Register the dog interface.
|
|
status = RpcServerRegisterIf(xIDog_v0_1_s_ifspec,
|
|
NULL, // MgrTypeUuid
|
|
NULL); // MgrEpv; null means use default
|
|
ASSERT( status, "Could not register RPC interface" );
|
|
|
|
// Inquire the endpoints.
|
|
status = RpcServerInqBindings(&bindings);
|
|
ASSERT( status, "Could not inquire bindings" );
|
|
|
|
// Register them in the endpoint mapper.
|
|
status = RpcEpRegister( xIDog_v0_1_s_ifspec, bindings, NULL, NULL );
|
|
ASSERT( status, "Could not register with endpoint mapper" );
|
|
|
|
// Start RPC listening.
|
|
status = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE );
|
|
ASSERT( status, "Could not start RPC listening" );
|
|
|
|
// Wait until the objects are released.
|
|
server_loop();
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nRemoteServer Test Passed.\n" );
|
|
else
|
|
printf( "\n\nRemoteServer Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_ring()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest **array = NULL;
|
|
SAptId *id_array = NULL;
|
|
HRESULT result;
|
|
int i;
|
|
int j;
|
|
int k;
|
|
int l;
|
|
int num_machines;
|
|
WCHAR this_machine[MAX_NAME];
|
|
DWORD ignore;
|
|
int pos;
|
|
int length;
|
|
const IID *(all_class_ids[2]);
|
|
const IID *class_id = ServerClsid;
|
|
|
|
// Initialize OLE.
|
|
hello( "ring" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
CoUninitialize();
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Recalling Initialize failed" );
|
|
result = initialize_security();
|
|
ASSERT( result, "Could not initialize security" );
|
|
|
|
// Compute the class ids to use.
|
|
all_class_ids[0] = ServerClsid;
|
|
i = ServerClsid - &ClassIds[0];
|
|
all_class_ids[1] = &ClassIds[(i+5) % NUM_CLASS_IDS];
|
|
|
|
// Lookup this machine's name.
|
|
ignore = sizeof(this_machine);
|
|
GetComputerName( this_machine, &ignore );
|
|
|
|
// If the server is this machine, set the number of machines to 1.
|
|
if (wcscmp(this_machine, Name) == 0)
|
|
num_machines = 1;
|
|
else
|
|
num_machines = 2;
|
|
|
|
// Allocate memory to hold all the server pointers.
|
|
length = NumProcesses * NumThreads * NumObjects * num_machines;
|
|
array = (ITest **) malloc( sizeof(ITest *) * length );
|
|
ASSERT_EXPR( array != NULL, "Could not allocate array." );
|
|
for (i = 0; i < length; i++)
|
|
array[i] = NULL;
|
|
|
|
// Allocate memory to hold all the server ids.
|
|
id_array = (SAptId *) malloc( sizeof(SAptId) * length );
|
|
ASSERT_EXPR( id_array != NULL, "Could not allocate id array." );
|
|
|
|
// Loop over all the machines.
|
|
pos = 0;
|
|
for (l = 0; l < num_machines; l++)
|
|
{
|
|
// Loop over all the processes.
|
|
for (i = 0; i < NumProcesses; i++)
|
|
{
|
|
// If the change flag was set, switch between apartment and
|
|
// free threaded servers.
|
|
if (Change)
|
|
class_id = all_class_ids[i&1];
|
|
|
|
// Create another server.
|
|
if (l == 0)
|
|
result = CoCreateInstance( *class_id, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &array[pos] );
|
|
else
|
|
result = create_instance( *class_id, &array[pos], &id_array[pos] );
|
|
ASSERT( result, "Could not create new server process" );
|
|
result = array[pos]->get_id( &id_array[pos] );
|
|
ASSERT( result, "Could not get id for new process" );
|
|
pos += 1;
|
|
|
|
for (j = 0; j < NumThreads; j++)
|
|
{
|
|
if (j != 0)
|
|
{
|
|
result = array[pos-1]->get_obj_from_new_apt( &array[pos],
|
|
&id_array[pos] );
|
|
ASSERT( result, "Could not get in process server" );
|
|
pos += 1;
|
|
}
|
|
for (k = 1; k < NumObjects; k++)
|
|
{
|
|
result = array[pos-1]->get_obj_from_this_apt( &array[pos],
|
|
&id_array[pos] );
|
|
ASSERT( result, "Could not get in thread server" );
|
|
pos += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hook up the ring.
|
|
for (i = 0; i < length-1; i++)
|
|
{
|
|
result = array[i]->remember( array[i+1], id_array[i+1] );
|
|
ASSERT( result, "Could not connect ring" );
|
|
}
|
|
result = array[length-1]->remember( array[0], id_array[0] );
|
|
ASSERT( result, "Could not connect ring" );
|
|
|
|
// Call around the ring.
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
result = array[0]->ring( length );
|
|
ASSERT( result, "Could not call around the ring" );
|
|
}
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
|
|
// Release all the servers. Start from the end so the main threads do
|
|
// not go away till all the secondary threads are done.
|
|
if (array != NULL)
|
|
for (i = length-1; i >= 0; i--)
|
|
if (array[i] != NULL)
|
|
{
|
|
result = array[i]->forget();
|
|
if (result != S_OK)
|
|
printf( "Could not forget server %x: 0x%x\n", i, result );
|
|
array[i]->Release();
|
|
}
|
|
|
|
// Release the memory holding the interface pointers.
|
|
if (array != NULL)
|
|
free(array);
|
|
|
|
// Release the memory for ids.
|
|
if (id_array != NULL)
|
|
free( id_array );
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nRing Test Passed.\n" );
|
|
else
|
|
printf( "\n\nRing Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_rpc()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
CTest *local = NULL;
|
|
SAptId id1;
|
|
SAptId id2;
|
|
HRESULT result;
|
|
WCHAR *binding = NULL;
|
|
RPC_BINDING_HANDLE handle = NULL;
|
|
RPC_STATUS status;
|
|
|
|
// Initialize OLE.
|
|
hello( "rpc" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a free threaded server.
|
|
result = CoCreateInstance( ClassIds[free_auto_none], NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = client1->get_id( &id1 );
|
|
ASSERT( result, "Could not get id of server" );
|
|
|
|
// Ask the server to register rpc.
|
|
result = client1->register_rpc( TestProtseq, &binding );
|
|
ASSERT( result, "Could not register rpc interface" );
|
|
|
|
// Create a binding handle.
|
|
status = RpcBindingFromStringBinding( binding, &handle );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make binding handle from string binding: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Make a raw rpc call.
|
|
result = check_client( handle, (unsigned long *) &status );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not make RPC call: 0x%x\n", status );
|
|
goto cleanup;
|
|
}
|
|
ASSERT( result, "Server could not check client's id" );
|
|
|
|
// Create a local object.
|
|
local = new CTest;
|
|
ASSERT_EXPR( local != NULL, "Could not create local object." );
|
|
result = local->get_id( &id2 );
|
|
ASSERT( result, "Could not get local id" );
|
|
|
|
// Pass an interface through a raw rpc call.
|
|
result = test( handle, local, id2, (unsigned long *) &status );
|
|
ASSERT( status, "Com fault testing interface with raw rpc" );
|
|
ASSERT( result, "Could not pass interface through raw rpc" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (local != NULL)
|
|
local->Release();
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (binding != NULL)
|
|
CoTaskMemFree( binding );
|
|
if (handle != NULL)
|
|
RpcBindingFree( &handle );
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nRpc Test Passed.\n" );
|
|
else
|
|
printf( "\n\nRpc Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*
|
|
This routine tests various cases of the client or server going away.
|
|
All permutations of the following variables are tested.
|
|
|
|
Clean exit (release and uninit) vs Dirty exit
|
|
1 COM thread/process vs 2 COM threads/process
|
|
Client dies vs Server dies
|
|
In process death vs Out of process death
|
|
*/
|
|
void do_rundown()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client = NULL;
|
|
ITest *client2 = NULL;
|
|
SAptId client_id;
|
|
SAptId client_id2;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "rundown" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = client->get_id( &client_id );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Run clean tests with one thread per process.
|
|
success = do_rundown1( &client, &client_id, 0 );
|
|
if (!success)
|
|
goto cleanup;
|
|
|
|
// Run clean tests with two threads per process.
|
|
success = do_rundown2( &client, &client_id, 0 );
|
|
if (!success)
|
|
goto cleanup;
|
|
|
|
// Run dirty tests with one thread per process.
|
|
success = do_rundown1( &client, &client_id, dirty_s );
|
|
if (!success)
|
|
goto cleanup;
|
|
|
|
// Run dirty tests with two threads per process.
|
|
success = do_rundown2( &client, &client_id, dirty_s );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Create helper.
|
|
result = client->get_obj_from_new_apt( &client2, &client_id2 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Start the test.
|
|
result = client->recurse_disconnect( client2, NumRecursion );
|
|
ASSERT( result, "Could not disconnect in a call" );
|
|
client2->Release();
|
|
client2 = NULL;
|
|
client->Release();
|
|
client = NULL;
|
|
|
|
// Create a client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = client->get_id( &client_id );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Tell the client to reinitialize.
|
|
result = client->reinitialize();
|
|
ASSERT( result, "Could not reinitialize client" );
|
|
|
|
// Give the reinitialize a chance to complete before continuing.
|
|
printf( "Waiting 5 seconds for reinitialize to complete.\n" );
|
|
Sleep(5000);
|
|
|
|
// Create another object on the same client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client2 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
|
|
// Check the client.
|
|
result = client2->get_id( &client_id );
|
|
ASSERT( result, "Could not get_id from client" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client2 != NULL)
|
|
client2->Release();
|
|
if (client != NULL)
|
|
client->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nRundown Test Passed.\n" );
|
|
else
|
|
printf( "\n\nRundown Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*
|
|
This is a helper routine for do_rundown. It always executes with one
|
|
thread per process of each type (thus a process might have one client and
|
|
one server thread). It takes a parameter to indicate whether to execute
|
|
clean or dirty deaths. It executes all permuations of the remaining
|
|
variables, listed below. Note that the order of execution is important
|
|
to reduce the number of process creations. Note that the routine takes
|
|
a client process on entry and returns a different client process on
|
|
exit.
|
|
|
|
Client death vs Server death
|
|
In process vs Out of process
|
|
*/
|
|
BOOL do_rundown1( ITest **client, SAptId *client_id, DWORD dirty )
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
HRESULT result;
|
|
SAptId server_id;
|
|
/**/
|
|
// Create in process server.
|
|
result = (*client)->get_obj_from_new_apt( &server, &server_id );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Ping.
|
|
result = (*client)->remember( server, server_id );
|
|
ASSERT( result, "Could not remember server" );
|
|
result = (*client)->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Kill server.
|
|
result = server->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on server" );
|
|
result = server->exit();
|
|
server->Release();
|
|
server = NULL;
|
|
ASSERT( result, "Could not exit server" );
|
|
|
|
// Query client.
|
|
result = (*client)->call_dead();
|
|
ASSERT( result, "Wrong error calling dead server" );
|
|
/**/
|
|
// Switch the client to server so the process doesn't go away when we kill
|
|
// the client. Then create an in process client.
|
|
server = *client;
|
|
server_id = *client_id;
|
|
*client = NULL;
|
|
/**/
|
|
result = server->get_obj_from_new_apt( client, client_id );
|
|
ASSERT( result, "Could not get in process client" );
|
|
|
|
// Ping.
|
|
result = (*client)->remember( server, server_id );
|
|
ASSERT( result, "Could not remember server" );
|
|
result = (*client)->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Kill client.
|
|
result = (*client)->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on client" );
|
|
(*client)->Release();
|
|
*client = NULL;
|
|
|
|
// Query server.
|
|
result = server->check( server_id );
|
|
ASSERT( result, "Could not check server" );
|
|
|
|
// Create out of process client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) client );
|
|
ASSERT( result, "Could not create out of process client" );
|
|
result = (*client)->get_id( client_id );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Ping.
|
|
result = (*client)->remember( server, server_id );
|
|
ASSERT( result, "Could not remember server" );
|
|
result = (*client)->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Kill client.
|
|
result = (*client)->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on client" );
|
|
(*client)->Release();
|
|
*client = NULL;
|
|
|
|
// Query server.
|
|
result = server->check( server_id );
|
|
ASSERT( result, "Could not check server" );
|
|
/**/
|
|
// Create out of process client.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) client );
|
|
ASSERT( result, "Could not create out of process client" );
|
|
result = (*client)->get_id( client_id );
|
|
ASSERT( result, "Could not get client id" );
|
|
|
|
// Ping.
|
|
result = (*client)->remember( server, server_id );
|
|
ASSERT( result, "Could not remember server" );
|
|
result = (*client)->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Kill server.
|
|
result = server->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on server" );
|
|
result = server->exit();
|
|
server->Release();
|
|
server = NULL;
|
|
if ((dirty & dirty_s) == 0)
|
|
ASSERT( result, "Could not exit server" );
|
|
|
|
// Query client.
|
|
result = (*client)->call_dead();
|
|
ASSERT( result, "Wrong error calling dead server" );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server != NULL)
|
|
server->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*
|
|
This is a helper routine for do_rundown. It always executes with two
|
|
threads per process of each type (thus a process might have two client and
|
|
two server threads). It takes a parameter to indicate whether to execute
|
|
clean or dirty deaths. It executes all permuations of the remaining
|
|
variables, listed below. Note that the order of execution is important
|
|
to reduce the number of process creations. Note that the routine takes
|
|
a client process on entry and returns a different client process on
|
|
exit.
|
|
|
|
Client death vs Server death
|
|
In process vs Out of process
|
|
*/
|
|
BOOL do_rundown2( ITest **client1, SAptId *client1_id, DWORD dirty )
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server1 = NULL;
|
|
ITest *server2 = NULL;
|
|
ITest *client2 = NULL;
|
|
SAptId client2_id;
|
|
SAptId server1_id;
|
|
SAptId server2_id;
|
|
HRESULT result;
|
|
|
|
// Create in process client.
|
|
result = (*client1)->get_obj_from_new_apt( &client2, &client2_id );
|
|
ASSERT( result, "Could not get in process client2" );
|
|
|
|
// Create in process server.
|
|
result = (*client1)->get_obj_from_new_apt( &server1, &server1_id );
|
|
ASSERT( result, "Could not get in process server1" );
|
|
|
|
// Create in process server.
|
|
result = (*client1)->get_obj_from_new_apt( &server2, &server2_id );
|
|
ASSERT( result, "Could not get in process server2" );
|
|
|
|
// Ping 1.
|
|
result = (*client1)->remember( server1, server1_id );
|
|
ASSERT( result, "Could not remember server1" );
|
|
result = (*client1)->call_next();
|
|
ASSERT( result, "Could not call server1" );
|
|
|
|
// Ping 2.
|
|
result = client2->remember( server2, server2_id );
|
|
ASSERT( result, "Could not remember server2" );
|
|
result = client2->call_next();
|
|
ASSERT( result, "Could not call server2" );
|
|
|
|
// Kill server1.
|
|
result = server1->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on server1" );
|
|
result = server1->exit();
|
|
server1->Release();
|
|
server1 = NULL;
|
|
ASSERT( result, "Could not exit server1" );
|
|
|
|
// Query client1.
|
|
result = (*client1)->call_dead();
|
|
ASSERT( result, "Wrong error calling dead server1" );
|
|
|
|
// Query client2.
|
|
result = client2->call_next();
|
|
ASSERT( result, "Could not call server2" );
|
|
|
|
// Query server2.
|
|
result = server2->check( server2_id );
|
|
ASSERT( result, "Could not check server2" );
|
|
|
|
// Switch the client1 to server1 so the process doesn't go away when we kill
|
|
// the client1. Then create an in process client1.
|
|
server1 = *client1;
|
|
server1_id = *client1_id;
|
|
*client1 = NULL;
|
|
result = server1->get_obj_from_new_apt( client1, client1_id );
|
|
ASSERT( result, "Could not get in process client1" );
|
|
|
|
// Ping 1.
|
|
result = (*client1)->remember( server1, server1_id );
|
|
ASSERT( result, "Could not remember server1" );
|
|
result = (*client1)->call_next();
|
|
ASSERT( result, "Could not call server1" );
|
|
|
|
// Ping 2.
|
|
result = client2->call_next();
|
|
ASSERT( result, "Could not call server2" );
|
|
|
|
// Kill client1.
|
|
result = (*client1)->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on client1" );
|
|
(*client1)->Release();
|
|
*client1 = NULL;
|
|
|
|
// Query server1.
|
|
result = server1->check( server1_id );
|
|
ASSERT( result, "Could not check server1" );
|
|
|
|
// Query server2.
|
|
result = server2->check( server2_id );
|
|
ASSERT( result, "Could not check server2" );
|
|
|
|
// Query client2.
|
|
result = client2->call_next();
|
|
ASSERT( result, "Could not call server2" );
|
|
client2->Release();
|
|
client2 = NULL;
|
|
|
|
// Create out of process client1.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) client1 );
|
|
ASSERT( result, "Could not create out of process client1" );
|
|
result = (*client1)->get_id( client1_id );
|
|
ASSERT( result, "Could not get client1 id" );
|
|
|
|
// Create in process client 2.
|
|
result = (*client1)->get_obj_from_new_apt( &client2, &client2_id );
|
|
ASSERT( result, "Could not get in process client2" );
|
|
|
|
// Ping 1.
|
|
result = (*client1)->remember( server1, server1_id );
|
|
ASSERT( result, "Could not remember server1" );
|
|
result = (*client1)->call_next();
|
|
ASSERT( result, "Could not call server1" );
|
|
|
|
// Ping 2.
|
|
result = client2->remember( server2, server2_id );
|
|
ASSERT( result, "Could not remember server2" );
|
|
result = client2->call_next();
|
|
ASSERT( result, "Could not call server2" );
|
|
|
|
// Kill client2 so process does not exit.
|
|
result = client2->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on client2" );
|
|
client2->Release();
|
|
client2 = NULL;
|
|
|
|
// Query server1.
|
|
result = server1->check( server1_id );
|
|
ASSERT( result, "Could not check server1" );
|
|
|
|
// Query server2.
|
|
result = server2->check( server2_id );
|
|
ASSERT( result, "Could not check server2" );
|
|
|
|
// Query client1.
|
|
result = (*client1)->call_next();
|
|
ASSERT( result, "Could not call server1" );
|
|
|
|
// Create in process client 2.
|
|
result = (*client1)->get_obj_from_new_apt( &client2, &client2_id );
|
|
ASSERT( result, "Could not get in process client2" );
|
|
|
|
// Ping 1.
|
|
result = (*client1)->call_next();
|
|
ASSERT( result, "Could not call server1" );
|
|
|
|
// Ping 2.
|
|
result = client2->remember( server2, server2_id );
|
|
ASSERT( result, "Could not remember server2" );
|
|
result = client2->call_next();
|
|
ASSERT( result, "Could not call server2" );
|
|
|
|
// Kill server2 so the server process does not go away.
|
|
result = server2->set_state( dirty, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set_state on server2" );
|
|
result = server2->exit();
|
|
server2->Release();
|
|
server2 = NULL;
|
|
if ((dirty & dirty_s) == 0)
|
|
ASSERT( result, "Could not exit server2" );
|
|
|
|
// Query client1.
|
|
result = (*client1)->call_next();
|
|
ASSERT( result, "Could not call server1" );
|
|
|
|
// Query client2.
|
|
result = client2->call_dead();
|
|
ASSERT( result, "Wrong error calling dead server2" );
|
|
|
|
// Query server1.
|
|
result = server1->check( server1_id );
|
|
ASSERT( result, "Could not check server1" );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server1 != NULL)
|
|
server1->Release();
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (client2 != NULL)
|
|
client2->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_securerefs()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
ITest *server2 = NULL;
|
|
ITest *local = NULL;
|
|
SAptId id_server;
|
|
SAptId id_server2;
|
|
SAptId id_local;
|
|
HRESULT result;
|
|
SOLE_AUTHENTICATION_SERVICE svc_list;
|
|
|
|
hello( "securerefs" );
|
|
|
|
// Try CoInitializeSecurity before CoInit.
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT_EXPR( result != S_OK, "Initialized security before OLE" );
|
|
|
|
// Initialize OLE.
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Set security to automatic none.
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT( result, "Could not initialize security to none" );
|
|
|
|
if (ThreadMode == COINIT_APARTMENTTHREADED)
|
|
{
|
|
// Create a local server
|
|
result = new_apartment_test( &local, &id_local, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
// Call the local server.
|
|
result = local->check( id_local );
|
|
ASSERT( result, "Could not call local server" )
|
|
|
|
// Release the local server.
|
|
local->Release();
|
|
local = NULL;
|
|
}
|
|
|
|
// Create a server possibly on a remote machine.
|
|
result = create_instance( *ServerClsid, &server, &id_server );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
|
|
|
|
// Call the server.
|
|
result = server->check( id_server );
|
|
ASSERT( result, "Could not call local server" )
|
|
|
|
// Release the server.
|
|
server->Release();
|
|
server = NULL;
|
|
|
|
// Uninitialize.
|
|
CoUninitialize();
|
|
|
|
// Reinitialize.
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Reinitialize failed" );
|
|
|
|
// Initialize security with secure refs but bad authn level.
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_SECURE_REFS, NULL );
|
|
ASSERT_EXPR( result != S_OK, "CoInitializeSecurity succeeded with bad parameters" );
|
|
|
|
// Initialize security with secure refs.
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_SECURE_REFS, NULL );
|
|
ASSERT( result, "Could not initialize secure refs" );
|
|
|
|
if (ThreadMode == COINIT_APARTMENTTHREADED)
|
|
{
|
|
// Create a local server
|
|
result = new_apartment_test( &local, &id_local, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
// Call the local server.
|
|
result = local->check( id_local );
|
|
ASSERT( result, "Could not call local server" )
|
|
|
|
// Release the local server.
|
|
local->Release();
|
|
local = NULL;
|
|
}
|
|
|
|
// Create a server possibly on a remote machine.
|
|
result = create_instance( *ServerClsid, &server, &id_server );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
|
|
|
|
// Call the server.
|
|
result = server->check( id_server );
|
|
ASSERT( result, "Could not call local server" )
|
|
|
|
// Release the server.
|
|
server->Release();
|
|
server = NULL;
|
|
|
|
// Create a server possibly on a remote machine.
|
|
result = create_instance( *ServerClsid, &server, &id_server );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
|
|
|
|
// Create a server on this machine.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &server2 );
|
|
ASSERT( result, "Could not create out of process server2" );
|
|
result = server2->get_id( &id_server2 );
|
|
ASSERT( result, "Could not get server2 id" );
|
|
|
|
// Have the second server remember the first.
|
|
result = server2->remember( server, id_server );
|
|
ASSERT( result, "Could not remember server" );
|
|
result = server2->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Release some extra public references.
|
|
success = do_securerefs_helper( &server );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// The server should be gone, have the second server try to call.
|
|
result = server2->call_next();
|
|
ASSERT_EXPR( result != S_OK, "Call to dead server succeeded" );
|
|
|
|
// Have the second server forget the first.
|
|
result = server2->forget();
|
|
ASSERT( result, "Could not forget server" );
|
|
|
|
// Create a possible machine remote server.
|
|
result = create_instance( *ServerClsid, &server, &id_server );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
|
|
|
|
// Tell the second server to remember it.
|
|
result = server2->remember( server, id_server );
|
|
ASSERT( result, "Could not remember server" );
|
|
result = server2->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Release all local references.
|
|
server->Release();
|
|
server = NULL;
|
|
|
|
// Have the second server call it.
|
|
result = server2->call_next();
|
|
ASSERT( result, "Could not call server" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nSecureRefs Test Passed.\n" );
|
|
else
|
|
printf( "\n\nSecureRefs Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_securerefs_helper( ITest **server )
|
|
{
|
|
ULONG size;
|
|
HRESULT result;
|
|
HANDLE memory = NULL;
|
|
BOOL success;
|
|
IStream *stream = NULL;
|
|
LARGE_INTEGER pos;
|
|
|
|
// Find out how much memory to allocate.
|
|
result = CoGetMarshalSizeMax( &size, IID_ITest, *server, 0, NULL,
|
|
MSHLFLAGS_NORMAL );
|
|
ASSERT( result, "Could not get marshal size" );
|
|
|
|
// Allocate memory.
|
|
memory = GlobalAlloc( GMEM_FIXED, size );
|
|
ASSERT_EXPR( memory != NULL, "Could not get memory." );
|
|
|
|
// Create a stream.
|
|
result = CreateStreamOnHGlobal( memory, TRUE, &stream );
|
|
ASSERT( result, "Could not create stream" );
|
|
|
|
// Marshal the proxy.
|
|
result = CoMarshalInterface( stream, IID_ITest, *server, 0, NULL,
|
|
MSHLFLAGS_NORMAL );
|
|
ASSERT( result, "Could not marshal interface" );
|
|
|
|
// Release the proxy.
|
|
(*server)->Release();
|
|
*server = NULL;
|
|
|
|
// Seek back to the start of the stream.
|
|
pos.QuadPart = 0;
|
|
result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
|
|
ASSERT( result, "Could not seek to start" );
|
|
|
|
// Unmarshal another copy.
|
|
result = CoUnmarshalInterface( stream, IID_ITest, (void **) server );
|
|
ASSERT( result, "Could not unmarshal from stream" );
|
|
|
|
// Release the proxy.
|
|
(*server)->Release();
|
|
*server = NULL;
|
|
|
|
// Seek back to the start of the stream.
|
|
pos.QuadPart = 0;
|
|
result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
|
|
ASSERT( result, "Could not seek to start" );
|
|
|
|
// Unmarshal another copy.
|
|
result = CoUnmarshalInterface( stream, IID_ITest, (void **) server );
|
|
ASSERT( result, "Could not unmarshal from stream" );
|
|
|
|
// Release the proxy.
|
|
(*server)->Release();
|
|
*server = NULL;
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
// The stream releases the memory.
|
|
if (stream != NULL)
|
|
stream->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_security()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
ITest *local = NULL;
|
|
ITest *server2 = NULL;
|
|
ITest *local2 = NULL;
|
|
SAptId id_server;
|
|
SAptId id_local;
|
|
SAptId id_server2;
|
|
SAptId id_local2;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "security" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Test automatic security.
|
|
success = do_security_auto();
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Uninitialize.
|
|
CoUninitialize();
|
|
|
|
// Reinitialize.
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Reinitialize failed" );
|
|
|
|
// Set security to automatic none.
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT( result, "Could not initialize security to none" );
|
|
|
|
// Create a local server
|
|
result = new_apartment_test( &local, &id_local, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
// Create a client possibly on a remote machine.
|
|
result = create_instance( *ServerClsid, &server, &id_server );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
|
|
|
|
// Test proxy copy for a local object.
|
|
if (ThreadMode != COINIT_MULTITHREADED)
|
|
{
|
|
success = do_security_copy( local, id_local );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
}
|
|
|
|
// Test proxy copy for a remote object.
|
|
success = do_security_copy( server, id_server );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Test delegation
|
|
if (ThreadMode != COINIT_MULTITHREADED)
|
|
{
|
|
// Create a local server
|
|
result = new_apartment_test( &local2, &id_local2, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
success = do_security_delegate( local, id_local, local2, id_local2 );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
}
|
|
|
|
// Create a client possibly on a remote machine.
|
|
result = create_instance( *ServerClsid, &server2, &id_server2 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server2 != NULL, "Create instance returned NULL." );
|
|
|
|
// Test delegation
|
|
success = do_security_delegate( server, id_server, server2, id_server2 );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Try some calls.
|
|
if (ThreadMode != COINIT_MULTITHREADED)
|
|
{
|
|
success = do_security_handle( local, id_local );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
}
|
|
|
|
// Try some calls.
|
|
success = do_security_handle( server, id_server );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Test nested impersonation for a local object.
|
|
if (ThreadMode != COINIT_MULTITHREADED)
|
|
{
|
|
success = do_security_nested( local, id_local );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
}
|
|
|
|
// Test nested impersonation for a remote object.
|
|
success = do_security_nested( server, id_server );
|
|
if (!success)
|
|
goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (local2 != NULL)
|
|
local2->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nSecurity Test Passed.\n" );
|
|
else
|
|
printf( "\n\nSecurity Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_auto( )
|
|
{
|
|
BOOL success = FALSE;
|
|
DWORD i;
|
|
DWORD j;
|
|
DWORD k;
|
|
HRESULT result;
|
|
SOLE_AUTHENTICATION_SERVICE svc_list;
|
|
ITest *server = NULL;
|
|
SAptId id_server;
|
|
DWORD authn_level;
|
|
DWORD authn_level_out;
|
|
HANDLE thread = NULL;
|
|
|
|
// Figure out the class id offset based on the threading model.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
k = 5;
|
|
else
|
|
k = 0;
|
|
|
|
// Try all types of security initialization.
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
|
|
// Initialize security.
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
authn_level = RPC_C_AUTHN_LEVEL_NONE;
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT( result, "Could not initialize security to none" );
|
|
break;
|
|
case 1:
|
|
authn_level = RPC_C_AUTHN_LEVEL_CONNECT;
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT( result, "Could not initialize security to connect" );
|
|
break;
|
|
case 2:
|
|
authn_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT( result, "Could not initialize security to integrity" );
|
|
break;
|
|
case 3:
|
|
authn_level = RPC_C_AUTHN_LEVEL_NONE;
|
|
svc_list.dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
svc_list.dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
svc_list.pPrincipalName = NULL;
|
|
result = MCoInitializeSecurity( NULL, 1, &svc_list, NULL,
|
|
RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
ASSERT( result, "Could not initialize security with authentication services" );
|
|
break;
|
|
case 4:
|
|
// Try legacy security by doing nothing.
|
|
authn_level = RPC_C_AUTHN_LEVEL_NONE;
|
|
break;
|
|
}
|
|
|
|
// Try all types of servers.
|
|
for (j = 0; j < 5; j++)
|
|
{
|
|
// Create a server.
|
|
result = create_instance( ClassIds[j+k], &server, &id_server );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
|
|
|
|
// Call it once.
|
|
success = do_security_lazy_call( server, id_server, authn_level,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
if (j == 1 || j == 2)
|
|
{
|
|
// Set the security too low.
|
|
result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket with authentication level none" );
|
|
|
|
// Make a bad call. Allow the security provider to up the level.
|
|
result = server->secure( id_server, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, (HACKSID *) ProcessSid, &authn_level_out );
|
|
ASSERT_EXPR( result != S_OK ||
|
|
(j == 1 && authn_level_out >= RPC_C_AUTHN_LEVEL_CONNECT) ||
|
|
(j == 2 && authn_level_out >= RPC_C_AUTHN_LEVEL_PKT_INTEGRITY),
|
|
"Bad call succeeded." );
|
|
}
|
|
|
|
// Release it.
|
|
server->Release();
|
|
server = NULL;
|
|
}
|
|
|
|
if (ThreadMode == COINIT_APARTMENTTHREADED)
|
|
{
|
|
// Create a local server.
|
|
result = new_apartment_test( &server, &id_server, &thread );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
|
|
// Make a local call.
|
|
success = do_security_lazy_call( server, id_server, authn_level,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Release it.
|
|
server->Release();
|
|
server = NULL;
|
|
|
|
// Wait for the helper thread to die.
|
|
result = WaitForSingleObject( thread, INFINITE );
|
|
ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for thread." );
|
|
CloseHandle( thread );
|
|
thread = NULL;
|
|
}
|
|
|
|
// Uninitialize OLE.
|
|
CoUninitialize();
|
|
|
|
// Reinitialize OLE.
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Reinitialize failed" );
|
|
}
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server != NULL)
|
|
server->Release();
|
|
if (thread != NULL)
|
|
CloseHandle( thread );
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_call( ITest *server, SAptId id, DWORD authn_level,
|
|
DWORD imp_level, DWORD authn_svc, DWORD authz_svc,
|
|
SID *sid )
|
|
{
|
|
BOOL success = FALSE;
|
|
HRESULT result;
|
|
DWORD authn_level_out;
|
|
DWORD imp_level_out;
|
|
DWORD authn_svc_out;
|
|
DWORD authz_svc_out;
|
|
OLECHAR *princ_name_out = NULL;
|
|
|
|
result = MCoSetProxyBlanket( server, authn_svc, authz_svc, NULL,
|
|
authn_level, imp_level, NULL, EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket" );
|
|
|
|
// Verify the authentication information.
|
|
result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
|
|
&princ_name_out, &authn_level_out,
|
|
&imp_level_out, NULL, NULL );
|
|
if (result == S_OK)
|
|
{
|
|
ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
|
|
ASSERT_EXPR( authn_level <= authn_level_out, "Wrong authentication level." );
|
|
ASSERT_EXPR( imp_level == imp_level_out, "Wrong impersonation level." );
|
|
ASSERT_EXPR( authn_svc == authn_svc_out, "Wrong authentication service." );
|
|
ASSERT_EXPR( authz_svc == authz_svc_out, "Wrong authorization service." );
|
|
}
|
|
|
|
// Make a call.
|
|
result = server->secure( id, authn_level, imp_level, authn_svc, authz_svc,
|
|
NULL, (HACKSID *) sid, &authn_level_out );
|
|
ASSERT( result, "Secure call failed" );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
CoTaskMemFree( princ_name_out );
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_copy( ITest *server, SAptId id )
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *copy1 = NULL;
|
|
ITest *copy2 = NULL;
|
|
ITest *copy3 = NULL;
|
|
HRESULT result;
|
|
|
|
// Make a copy.
|
|
result = MCoCopyProxy( server, (IUnknown **) ©1 );
|
|
ASSERT( result, "Could not copy proxy" );
|
|
|
|
// Verify that it calls at none.
|
|
success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Verify that the original calls at none.
|
|
success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Call on the original at connect.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Verify that the copy still calls at none.
|
|
success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Call on the copy at encrypt.
|
|
success = do_security_call( copy1, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Verify that the original still calls at connect.
|
|
success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Free the copy.
|
|
copy1->Release();
|
|
copy1 = NULL;
|
|
|
|
// Make a copy.
|
|
result = MCoCopyProxy( server, (IUnknown **) ©1 );
|
|
ASSERT( result, "Could not copy proxy" );
|
|
|
|
// Verify that the copy calls at none.
|
|
success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Copy the copy.
|
|
result = MCoCopyProxy( copy1, (IUnknown **) ©2 );
|
|
ASSERT( result, "Could not copy a copy of a proxy" );
|
|
|
|
// Verify the second copy calls at none.
|
|
success = do_security_lazy_call( copy2, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Change the first copy to integrity.
|
|
success = do_security_call( copy1, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Change the second copy to encrypt.
|
|
success = do_security_call( copy2, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Verify that the original is still connect.
|
|
success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Querying a copy should return the original.
|
|
result = copy1->QueryInterface( IID_ITest, (void **) ©3 );
|
|
ASSERT( result, "Could not QueryInterface" );
|
|
ASSERT_EXPR( server == copy3, "QueryInterface did not return the original." );
|
|
copy3->Release();
|
|
copy3 = NULL;
|
|
|
|
// Free the original.
|
|
server->Release();
|
|
server = NULL;
|
|
|
|
// Free the second copy.
|
|
copy2->Release();
|
|
copy2 = NULL;
|
|
|
|
// Make another copy.
|
|
result = MCoCopyProxy( copy1, (IUnknown **) ©2 );
|
|
ASSERT( result, "Could not copy a copy of a proxy" );
|
|
|
|
// Verify that it calls at none.
|
|
success = do_security_lazy_call( copy2, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Query for the original.
|
|
result = copy1->QueryInterface( IID_ITest, (void **) &server );
|
|
ASSERT( result, "Could not QueryInterface" );
|
|
|
|
// Verify that it calls at connect.
|
|
success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Verify that the first copy is still at integrity
|
|
success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
ProcessSid );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (copy1 != NULL)
|
|
copy1->Release();
|
|
if (copy2 != NULL)
|
|
copy2->Release();
|
|
if (copy3 != NULL)
|
|
copy3->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_delegate( ITest *server, SAptId id, ITest *server2,
|
|
SAptId id2 )
|
|
{
|
|
BOOL success = FALSE;
|
|
HRESULT result;
|
|
|
|
// Make a call.
|
|
result = server->delegate( server2, id2, (HACKSID *) ProcessSid );
|
|
ASSERT( result, "Delegate call failed" );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_handle( ITest *server, SAptId id )
|
|
{
|
|
BOOL success = FALSE;
|
|
|
|
// Make a call with no security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
// Make a call with connect security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
// Make a call with integrity security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
|
|
// Make a call with encrypt security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
// Make a call with no security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
// Make a call with connect security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
// Make a call with integrity security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
|
|
// Make a call with encrypt security.
|
|
success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IDENTIFY,
|
|
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
|
|
if (!success)
|
|
return FALSE;
|
|
|
|
// Finally, its all over.
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_lazy_call( ITest *server, SAptId id, DWORD authn_level,
|
|
DWORD imp_level, DWORD authn_svc, DWORD authz_svc,
|
|
SID *sid )
|
|
{
|
|
BOOL success = FALSE;
|
|
HRESULT result;
|
|
DWORD authn_level_out;
|
|
DWORD imp_level_out;
|
|
DWORD authn_svc_out;
|
|
DWORD authz_svc_out;
|
|
OLECHAR *princ_name_out = NULL;
|
|
|
|
// Verify the authentication information.
|
|
result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
|
|
&princ_name_out, &authn_level_out,
|
|
&imp_level_out, NULL, NULL );
|
|
if (result == S_OK)
|
|
{
|
|
ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
|
|
ASSERT_EXPR( authn_level <= authn_level_out, "Wrong authentication level." );
|
|
ASSERT_EXPR( imp_level == imp_level_out, "Wrong impersonation level." );
|
|
ASSERT_EXPR( authn_svc == authn_svc_out, "Wrong authentication service." );
|
|
ASSERT_EXPR( authz_svc == authz_svc_out, "Wrong authorization service." );
|
|
}
|
|
|
|
// Make a call.
|
|
result = server->secure( id, authn_level, imp_level, authn_svc, authz_svc,
|
|
NULL, (HACKSID *) sid, &authn_level_out );
|
|
ASSERT( result, "Secure call failed" );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
CoTaskMemFree( princ_name_out );
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_security_nested( ITest *server, SAptId id )
|
|
{
|
|
HRESULT result;
|
|
CTest test;
|
|
BOOL success = FALSE;
|
|
IServerSecurity *security = NULL;
|
|
TOKEN_USER *token_info = NULL;
|
|
DWORD info_size = 1024;
|
|
HANDLE token = NULL;
|
|
PSID me = NULL;
|
|
|
|
// Make a recursive call. The proxy is set to encrypt from the previous test.
|
|
result = server->recurse_secure( &test, 3, 1, (HACKSID *) ProcessSid );
|
|
ASSERT( result, "Could not make recursive call with impersonation." );
|
|
|
|
// Try to get call context.
|
|
result = MCoGetCallContext( IID_IServerSecurity, (void **) &security );
|
|
ASSERT_EXPR( result != S_OK, "Get call context succeeded outside a call." );
|
|
|
|
// Open the thread token.
|
|
if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
|
|
result = S_OK;
|
|
else
|
|
result = GetLastError();
|
|
ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
|
|
|
|
// Lookup SID of thread token.
|
|
token_info = (TOKEN_USER *) malloc( info_size );
|
|
ASSERT_EXPR( token_info != NULL, "Could not allocate memory for token info." );
|
|
if (result == NOERROR)
|
|
{
|
|
GetTokenInformation( token, TokenUser, token_info, info_size, &info_size );
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not GetTokenInformation" );
|
|
me = token_info->User.Sid;
|
|
|
|
// The SID on the thread token should equal the process token.
|
|
ASSERT_EXPR( EqualSid( me, ProcessSid ), "Wrong thread token." );
|
|
}
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (security != NULL)
|
|
security->Release();
|
|
if (token_info != NULL)
|
|
free(token_info);
|
|
if (token != NULL)
|
|
CloseHandle( token );
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_send()
|
|
{
|
|
LRESULT result;
|
|
|
|
// Say hello.
|
|
printf( "Sending a message to window 0x%x\n", NumIterations );
|
|
result = SendMessageA( (HWND) NumIterations, WM_USER, 0, 0 );
|
|
|
|
if (result == 0)
|
|
printf( "\n\nSendMessageA succeeded.\n" );
|
|
else
|
|
printf( "\n\nSendMessageA failed: 0x%x\n", result );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_server( )
|
|
{
|
|
HRESULT result;
|
|
BOOL success = FALSE;
|
|
SOLE_AUTHENTICATION_SERVICE svc_list;
|
|
|
|
// Initialize OLE.
|
|
hello( "server" );
|
|
printf( "Initializing thread 0x%x\n", GetCurrentThreadId() );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
result = initialize_security();
|
|
ASSERT( result, "Could not initialize security" );
|
|
|
|
// Create our class factory
|
|
ClassFactory = new CTestCF();
|
|
ASSERT_EXPR( ClassFactory != NULL, "Could not create class factory." );
|
|
|
|
// Register our class with OLE
|
|
result = CoRegisterClassObject(*ServerClsid, ClassFactory, CLSCTX_LOCAL_SERVER,
|
|
REGCLS_SINGLEUSE, &Registration);
|
|
ASSERT( result, "CoRegisterClassObject failed" );
|
|
|
|
// CoRegister bumps reference count so we don't have to!
|
|
ClassFactory->Release();
|
|
|
|
// Do whatever we have to do till it is time to pay our taxes and die.
|
|
server_loop();
|
|
|
|
// Deregister out class - should release object as well
|
|
if (!dirty_thread())
|
|
{
|
|
result = CoRevokeClassObject(Registration);
|
|
ASSERT( result, "CoRevokeClassObject failed" );
|
|
}
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (!dirty_thread())
|
|
{
|
|
printf( "Uninitializing thread 0x%x\n", GetCurrentThreadId() );
|
|
CoUninitialize();
|
|
}
|
|
else
|
|
printf( "\n\nI didn't clean up\n" );
|
|
|
|
if (success)
|
|
printf( "\n\nServer Passed.\n" );
|
|
else
|
|
printf( "\n\nServer Failed.\n" );
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
void do_sid()
|
|
{
|
|
BOOL success = FALSE;
|
|
BOOL call_success;
|
|
SID *pSID = NULL;
|
|
DWORD cbSID = 1024;
|
|
WCHAR *lpszDomain = NULL;
|
|
DWORD cchDomainName = 80;
|
|
SID_NAME_USE sid_use;
|
|
HRESULT result = S_OK;
|
|
DWORD i;
|
|
|
|
// Say hello.
|
|
printf( "Looking up sid for %ws.\n", Name );
|
|
|
|
// Lookup the name.
|
|
pSID = (SID *) LocalAlloc(LPTR, cbSID*2);
|
|
lpszDomain = (WCHAR *) LocalAlloc(LPTR, cchDomainName*2);
|
|
ASSERT_EXPR( pSID != NULL && lpszDomain != NULL, "LocalAlloc" );
|
|
call_success = LookupAccountName(NULL,
|
|
Name,
|
|
pSID,
|
|
&cbSID,
|
|
lpszDomain,
|
|
&cchDomainName,
|
|
&sid_use);
|
|
result = GetLastError();
|
|
ASSERT( result, "Could not LookupAccountName" );
|
|
ASSERT_EXPR( call_success, "LookupAccountName failed." );
|
|
ASSERT_EXPR( IsValidSid(pSID), "Got a bad SID." );
|
|
printf( "SID\n" );
|
|
printf( " Revision: 0x%02x\n", pSID->Revision );
|
|
printf( " SubAuthorityCount: 0x%x\n", pSID->SubAuthorityCount );
|
|
printf( " IdentifierAuthority: 0x%02x%02x%02x%02x%02x%02x\n",
|
|
pSID->IdentifierAuthority.Value[0],
|
|
pSID->IdentifierAuthority.Value[1],
|
|
pSID->IdentifierAuthority.Value[2],
|
|
pSID->IdentifierAuthority.Value[3],
|
|
pSID->IdentifierAuthority.Value[4],
|
|
pSID->IdentifierAuthority.Value[5] );
|
|
for (i = 0; i < pSID->SubAuthorityCount; i++)
|
|
printf( " SubAuthority[%d]: 0x%08x\n", i,
|
|
pSID->SubAuthority[i] );
|
|
printf( " Domain: %ws\n", lpszDomain );
|
|
printf( " SID_NAME_USE: 0x%x\n", sid_use );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
if (lpszDomain != NULL)
|
|
LocalFree((HLOCAL) lpszDomain);
|
|
if (pSID != NULL)
|
|
LocalFree(pSID);
|
|
|
|
if (success)
|
|
printf( "\n\nSid succeeded.\n" );
|
|
else
|
|
printf( "\n\nSid failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_simple_rundown()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
CTest *local = NULL;
|
|
SAptId id1;
|
|
SAptId local_id;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "simple rundown" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a server
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create server" );
|
|
result = client1->get_id( &id1 );
|
|
ASSERT( result, "Could not get id" );
|
|
|
|
// Create a local object.
|
|
local = new CTest;
|
|
ASSERT_EXPR( local != NULL, "Could not create a local object." );
|
|
result = local->get_id( &local_id );
|
|
ASSERT( result, "Could not get id" );
|
|
|
|
// Tell it to remember this object.
|
|
result = client1->remember( local, local_id );
|
|
ASSERT( result, "Could not remember local object" );
|
|
local->Release();
|
|
local = NULL;
|
|
|
|
// Tell the other apartment to die.
|
|
result = client1->set_state( dirty_s, THREAD_PRIORITY_NORMAL );
|
|
ASSERT( result, "Could not set exit dirty" );
|
|
result = client1->exit();
|
|
|
|
// Wait araound till no one references the local object.
|
|
printf( "Wait for object to rundown. This could take 12 minutes.\n" );
|
|
server_loop();
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (local != NULL)
|
|
local->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nSimple Rundown Test Passed.\n" );
|
|
else
|
|
printf( "\n\nSimple Rundown Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_thread()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
ITest *client2 = NULL;
|
|
ITest *client3 = NULL;
|
|
ITest *client4 = NULL;
|
|
SAptId id1;
|
|
SAptId id2;
|
|
SAptId id4;
|
|
HRESULT result;
|
|
GUID guid;
|
|
|
|
// Initialize OLE.
|
|
hello( "thread" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a client on this thread.
|
|
client3 = new CTest;
|
|
ASSERT_EXPR( client3 != NULL, "Could not create a local object." );
|
|
|
|
// Create a client on another thread in this process
|
|
result = client3->get_obj_from_new_apt( &client4, &id4 );
|
|
ASSERT( result, "Could not get in process client" );
|
|
|
|
// Create a server
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &client1 );
|
|
ASSERT( result, "Could not create instance of test server" );
|
|
result = client1->get_id( &id1 );
|
|
ASSERT( result, "Could not get id of server" );
|
|
|
|
// Create an object in another apartment in the server.
|
|
result = client1->get_obj_from_new_apt( &client2, &id2 );
|
|
ASSERT( result, "Could not get in process server" );
|
|
|
|
// Check each object.
|
|
result = client1->check( id1 );
|
|
ASSERT( result, "Could not check server 1" );
|
|
result = client2->check( id2 );
|
|
ASSERT( result, "Could not check server 2" );
|
|
|
|
// Pass a server to the other thread in this process.
|
|
result = client4->remember( client1, id1 );
|
|
ASSERT( result, "Client could not remember server" );
|
|
|
|
// Release the second object.
|
|
client2->Release();
|
|
client2 = NULL;
|
|
|
|
// Check the first object.
|
|
result = client1->check( id1 );
|
|
ASSERT( result, "Could not check server 1" );
|
|
|
|
// Check the first object from another thread.
|
|
result = client4->call_next();
|
|
ASSERT( result, "Could not check server 1 from thread 2" );
|
|
|
|
// Release the first object from this thread.
|
|
client1->Release();
|
|
client1 = NULL;
|
|
|
|
// Check the first object from another thread.
|
|
result = client4->call_next();
|
|
ASSERT( result, "Could not check server 1 from thread 2" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client2 != NULL)
|
|
client2->Release();
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
if (client3 != NULL)
|
|
client3->Release();
|
|
if (client4 != NULL)
|
|
client4->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nThread Test Passed.\n" );
|
|
else
|
|
printf( "\n\nThread Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
typedef struct
|
|
{
|
|
ATOM wclass;
|
|
HWND wdriver;
|
|
HWND whelper;
|
|
HANDLE hdriver;
|
|
HANDLE hhelper;
|
|
HRESULT result;
|
|
} SSwitchData;
|
|
|
|
SSwitchData gSwitch;
|
|
|
|
LRESULT do_three_wndproc(HWND window, UINT message, WPARAM unused, LPARAM params);
|
|
DWORD _stdcall do_three_helper( void *nothing );
|
|
|
|
void do_three()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
HRESULT result;
|
|
int i;
|
|
WNDCLASS wclass;
|
|
HANDLE thread = NULL;
|
|
DWORD thread_id;
|
|
MSG msg;
|
|
|
|
// Initialize OLE.
|
|
hello( "three" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a remote server.
|
|
result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
|
|
IID_ITest, (void **) &server );
|
|
ASSERT( result, "Could not create server" );
|
|
|
|
// Register a window class.
|
|
wclass.style = 0;
|
|
wclass.lpfnWndProc = do_three_wndproc;
|
|
wclass.cbClsExtra = 0;
|
|
wclass.cbWndExtra = 0;
|
|
wclass.hInstance = NULL;
|
|
wclass.hIcon = NULL;
|
|
wclass.hCursor = NULL;
|
|
wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
|
|
wclass.lpszMenuName = NULL;
|
|
wclass.lpszClassName = L"That's me";
|
|
gSwitch.wclass = RegisterClass( &wclass );
|
|
ASSERT_EXPR( gSwitch.wclass != 0, "Could not register class." );
|
|
|
|
// Create a window.
|
|
gSwitch.wdriver = CreateWindowEx(0,
|
|
L"That's me",
|
|
L"My window",
|
|
// must use WS_POPUP so the window does not get
|
|
// assigned a hot key by user.
|
|
(WS_DISABLED | WS_POPUP),
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
NULL, // hinst
|
|
NULL);
|
|
ASSERT_EXPR( gSwitch.wdriver != NULL, "Could not create window." );
|
|
|
|
// Create an event.
|
|
gSwitch.hdriver = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
ASSERT_EXPR( gSwitch.hdriver != NULL, "Could not create event." );
|
|
|
|
// Create a thread.
|
|
thread = CreateThread( NULL, 0, do_three_helper, NULL, 0, &thread_id );
|
|
ASSERT_EXPR( thread != NULL, "Could not create thread." );
|
|
CloseHandle( thread );
|
|
|
|
// Wait for the thread to initialize.
|
|
result = WaitForSingleObject( gSwitch.hdriver, INFINITE );
|
|
ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for thread." );
|
|
ASSERT( gSwitch.result, "Helper thread failed." );
|
|
|
|
// Test some thread switches
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
// Post a message to the thread.
|
|
success = PostMessageA( gSwitch.whelper, WM_USER, 0, 0 );
|
|
ASSERT_EXPR( success, "Could not post message." );
|
|
success = FALSE;
|
|
|
|
// Wait for a post message reply.
|
|
result = MsgWaitForMultipleObjects( 1, &gSwitch.hdriver, FALSE,
|
|
1000, QS_POSTMESSAGE );
|
|
ASSERT_EXPR( result == WAIT_OBJECT_0+1, "Could not wait for post message." );
|
|
ASSERT( gSwitch.result, "Helper thread failed." );
|
|
success = PeekMessage( &msg, gSwitch.wdriver, WM_USER, WM_USER,
|
|
PM_REMOVE | PM_NOYIELD );
|
|
ASSERT_EXPR( success, "Could not peek message." );
|
|
success = FALSE;
|
|
DispatchMessageA( &msg );
|
|
|
|
// Set an event to reply.
|
|
success = SetEvent( gSwitch.hhelper );
|
|
ASSERT_EXPR( success, "Could not set event." );
|
|
success = FALSE;
|
|
|
|
// Wait for a set event reply.
|
|
result = MsgWaitForMultipleObjects( 1, &gSwitch.hdriver, FALSE,
|
|
1000, QS_POSTMESSAGE );
|
|
ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for event." );
|
|
ASSERT( gSwitch.result, "Helper thread failed." );
|
|
}
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server != NULL)
|
|
server->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nThree Test Passed.\n" );
|
|
else
|
|
printf( "\n\nThree Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
LRESULT do_three_wndproc(HWND window, UINT message, WPARAM unused, LPARAM params)
|
|
{
|
|
return DefWindowProc( window, message, unused, params );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD _stdcall do_three_helper( void *nothing )
|
|
{
|
|
HRESULT result;
|
|
BOOL success;
|
|
MSG msg;
|
|
|
|
// Create an event.
|
|
gSwitch.hhelper = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
ASSERT_EXPR( gSwitch.hhelper != NULL, "Could not create event." );
|
|
|
|
// Create a window.
|
|
gSwitch.whelper = CreateWindowEx(0,
|
|
L"That's me",
|
|
L"My window",
|
|
// must use WS_POPUP so the window does not get
|
|
// assigned a hot key by user.
|
|
(WS_DISABLED | WS_POPUP),
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
NULL, // hinst
|
|
NULL);
|
|
ASSERT_EXPR( gSwitch.whelper != NULL, "Could not create window." );
|
|
|
|
// Wake up the driver.
|
|
gSwitch.result = S_OK;
|
|
success = SetEvent( gSwitch.hdriver );
|
|
ASSERT_EXPR( success, "Could not set event." );
|
|
|
|
// Loop forever.
|
|
while (TRUE)
|
|
{
|
|
// Wait for a message.
|
|
success = GetMessageA( &msg, NULL, 0, 0 );
|
|
ASSERT_EXPR( success, "Could not get message." );
|
|
TranslateMessage (&msg);
|
|
DispatchMessageA (&msg);
|
|
|
|
// Post a reply.
|
|
success = PostMessageA( gSwitch.wdriver, WM_USER, 0, 0 );
|
|
ASSERT_EXPR( success, "Could not post message." );
|
|
success = FALSE;
|
|
|
|
// Wait for an event.
|
|
result = MsgWaitForMultipleObjects( 1, &gSwitch.hhelper, FALSE,
|
|
1000, QS_POSTMESSAGE );
|
|
ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for event." );
|
|
|
|
// Set an event to reply.
|
|
success = SetEvent( gSwitch.hdriver );
|
|
ASSERT_EXPR( success, "Could not set event." );
|
|
}
|
|
|
|
cleanup:
|
|
gSwitch.result = E_FAIL;
|
|
success = SetEvent( gSwitch.hdriver );
|
|
return E_FAIL;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_two()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *client1 = NULL;
|
|
SAptId id1;
|
|
HRESULT result;
|
|
DWORD i;
|
|
LARGE_INTEGER freq;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER nothing;
|
|
LARGE_INTEGER init_sec_none;
|
|
LARGE_INTEGER open;
|
|
LARGE_INTEGER get_sid;
|
|
HANDLE hToken = NULL;
|
|
BYTE aMemory[1024];
|
|
TOKEN_USER *pTokenUser = (TOKEN_USER *) &aMemory;
|
|
DWORD lNameLen = 1000;
|
|
DWORD lDomainLen = 1000;
|
|
DWORD lIgnore;
|
|
DWORD lSidLen;
|
|
WCHAR name[1000];
|
|
WCHAR domain[1000];
|
|
LARGE_INTEGER lookup;
|
|
DWORD xlookup;
|
|
SID_NAME_USE sIgnore;
|
|
|
|
// Initialize OLE.
|
|
hello( "two" );
|
|
result = initialize(NULL,ThreadMode);
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Measure the performance of nothing.
|
|
QueryPerformanceFrequency( &freq );
|
|
QueryPerformanceCounter( &start );
|
|
QueryPerformanceCounter( ¬hing );
|
|
nothing.QuadPart = 1000000 * (nothing.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
|
|
// Open the process's token.
|
|
QueryPerformanceCounter( &start );
|
|
success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken );
|
|
QueryPerformanceCounter( &open );
|
|
open.QuadPart = 1000000 * (open.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT_EXPR( success, "Could not open process token." );
|
|
|
|
// Lookup SID of process token.
|
|
QueryPerformanceCounter( &start );
|
|
success = GetTokenInformation( hToken, TokenUser, pTokenUser, sizeof(aMemory),
|
|
&lIgnore );
|
|
QueryPerformanceCounter( &get_sid );
|
|
get_sid.QuadPart = 1000000 * (get_sid.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT_EXPR( success, "Could not get token information." );
|
|
|
|
// Lookup the name from the sid.
|
|
QueryPerformanceCounter( &start );
|
|
LookupAccountSid( NULL, pTokenUser->User.Sid, name, &lNameLen,
|
|
domain, &lDomainLen, &sIgnore );
|
|
ASSERT_EXPR( success, "Could not lookup account sid." );
|
|
QueryPerformanceCounter( &lookup );
|
|
lookup.QuadPart = 1000000 * (lookup.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
|
|
// Lookup the name from the sid a lot of times.
|
|
xlookup = GetTickCount();
|
|
for (i = 0; i < NumIterations; i++)
|
|
{
|
|
LookupAccountSid( NULL, pTokenUser->User.Sid, name, &lNameLen,
|
|
domain, &lDomainLen, &sIgnore );
|
|
ASSERT_EXPR( success, "Could not lookup account sid." );
|
|
}
|
|
xlookup = (GetTickCount() - xlookup)*1000/NumIterations;
|
|
|
|
// Import the security APIs.
|
|
GCoInitializeSecurity = (CoInitializeSecurityFn) Fixup( "CoInitializeSecurity" );
|
|
if (GCoInitializeSecurity == NULL)
|
|
goto cleanup;
|
|
|
|
// Measure the performance of initialize.
|
|
QueryPerformanceCounter( &start );
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
QueryPerformanceCounter( &init_sec_none );
|
|
init_sec_none.QuadPart = 1000000 * (init_sec_none.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
ASSERT( result, "Could not initialize security" );
|
|
|
|
// Print the timings.
|
|
printf( "nothing took %duS\n", nothing.u.LowPart );
|
|
printf( "OpenProcessToken took %duS\n", open.u.LowPart );
|
|
printf( "GetTokenInformation took %duS\n", get_sid.u.LowPart );
|
|
printf( "LookupAccountSid took %duS\n", lookup.u.LowPart );
|
|
printf( "LookupAccountSid multiple took %duS\n", xlookup );
|
|
printf( "CoInitializeSecurity at none took %duS\n", init_sec_none.u.LowPart );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (client1 != NULL)
|
|
client1->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nTwo Test Passed.\n" );
|
|
else
|
|
printf( "\n\nTwo Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_uninit()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
ITest *server2 = NULL;
|
|
SAptId id;
|
|
SAptId id2;
|
|
HRESULT result;
|
|
DWORD i;
|
|
HANDLE thread[MAX_THREADS];
|
|
DWORD thread_id;
|
|
|
|
// This test always runs in multithreaded mode. It tests a multithread
|
|
// only problem and uses freethreaded blocking.
|
|
ThreadMode = COINIT_MULTITHREADED;
|
|
|
|
// Initialize OLE.
|
|
hello( "uninit" );
|
|
result = initialize( NULL, ThreadMode );
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Create a possibly remote object.
|
|
result = create_instance( ClassIds[free_auto_none], &server, &id );
|
|
ASSERT( result, "Could not create server" );
|
|
|
|
// Get another object.
|
|
result = server->get_obj_from_this_apt( &server2, &id2 );
|
|
ASSERT( result, "Could not get another object" );
|
|
|
|
// Tell the server to remember its neighbor
|
|
result = server->remember( server2, id2 );
|
|
ASSERT( result, "Could not remember server" );
|
|
server2->Release();
|
|
server2 = NULL;
|
|
|
|
// Tell it to wait for a call during shutdown and lower its priority.
|
|
result = server->set_state( late_dispatch_s, THREAD_PRIORITY_LOWEST );
|
|
ASSERT( result, "Could not set server state" );
|
|
|
|
// Don't create too many threads.
|
|
if (NumThreads > MAX_THREADS)
|
|
NumThreads = MAX_THREADS;
|
|
|
|
// Create some helper threads.
|
|
GlobalBool = TRUE;
|
|
for (i = 0; i < NumThreads; i++)
|
|
{
|
|
thread[i] = CreateThread( NULL, 0, do_uninit_helper, server, 0, &thread_id );
|
|
if (thread[i] == NULL)
|
|
{
|
|
printf( "Could not create helper thread number %d.\n", i );
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// Call the server. Marshal an interface. Start shutting down.
|
|
// Wait before returning.
|
|
result = server->get_next_slowly( &server2, &id2 );
|
|
ASSERT( result, "Could not call server during shutdown" );
|
|
|
|
// Let the helpers run a while.
|
|
printf( "Waiting 5 seconds for server to die." );
|
|
Sleep( 5000 );
|
|
|
|
// Tell all the helpers to die.
|
|
GlobalBool = FALSE;
|
|
result = WaitForMultipleObjects( NumThreads, thread, TRUE, INFINITE );
|
|
ASSERT_EXPR( result != WAIT_FAILED, "Could not wait for helper threads to die.\n" );
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (server2 != NULL)
|
|
server2->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nUninit Test Passed.\n" );
|
|
else
|
|
printf( "\n\nUninit Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD _stdcall do_uninit_helper( void *param )
|
|
{
|
|
ITest *server = (ITest *) param;
|
|
ITest *server2;
|
|
SAptId id;
|
|
|
|
// Call the server till the process terminates.
|
|
while (GlobalBool)
|
|
server->get_next( &server2, &id );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void do_unknown()
|
|
{
|
|
BOOL success = FALSE;
|
|
ITest *server = NULL;
|
|
IUnknown *unknown = NULL;
|
|
SAptId id;
|
|
HRESULT result;
|
|
|
|
// Initialize OLE.
|
|
hello( "unknown" );
|
|
result = initialize( NULL, ThreadMode );
|
|
ASSERT( result, "Initialize failed" );
|
|
|
|
// Set security to connect with secure references.
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_SECURE_REFS, NULL );
|
|
ASSERT( result, "Could not initialize security to connect" );
|
|
|
|
if (ThreadMode == COINIT_APARTMENTTHREADED)
|
|
{
|
|
// Create a local server
|
|
result = new_apartment_test( &server, &id, NULL );
|
|
ASSERT( result, "Could not create local instance of test server" );
|
|
result = server->QueryInterface( IID_IUnknown, (void **) &unknown );
|
|
ASSERT( result, "Could not get IUnknown" );
|
|
|
|
// Test IUnknown
|
|
success = do_unknown_helper( unknown );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Release the local server.
|
|
unknown->Release();
|
|
unknown = NULL;
|
|
server->Release();
|
|
server = NULL;
|
|
}
|
|
|
|
// Create a possibly remote object.
|
|
result = create_instance( *ServerClsid, &server, &id );
|
|
ASSERT( result, "Could not create server" );
|
|
result = server->QueryInterface( IID_IUnknown, (void **) &unknown );
|
|
ASSERT( result, "Could not get IUnknown" );
|
|
|
|
// Test IUnknown
|
|
success = do_unknown_helper( unknown );
|
|
if (!success) goto cleanup;
|
|
success = FALSE;
|
|
|
|
// Finally, its all over.
|
|
success = TRUE;
|
|
cleanup:
|
|
if (unknown != NULL)
|
|
unknown->Release();
|
|
if (server != NULL)
|
|
server->Release();
|
|
CoUninitialize();
|
|
|
|
if (success)
|
|
printf( "\n\nUnknown Test Passed.\n" );
|
|
else
|
|
printf( "\n\nUnknown Test Failed.\n" );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_unknown_call( IUnknown *server, DWORD authn, DWORD imp, REFIID iid )
|
|
{
|
|
BOOL success = FALSE;
|
|
HRESULT result;
|
|
DWORD authn_level_out;
|
|
DWORD imp_level_out;
|
|
DWORD authn_svc_out;
|
|
DWORD authz_svc_out;
|
|
OLECHAR *princ_name_out = NULL;
|
|
ITest *test = NULL;
|
|
|
|
result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
|
NULL, authn, imp, NULL, EOAC_NONE );
|
|
ASSERT( result, "Could not set blanket" );
|
|
|
|
// Verify the authentication information.
|
|
result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
|
|
&princ_name_out, &authn_level_out,
|
|
&imp_level_out, NULL, NULL );
|
|
if (result == S_OK)
|
|
{
|
|
ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
|
|
ASSERT_EXPR( authn <= authn_level_out, "Wrong authentication level." );
|
|
ASSERT_EXPR( imp == imp_level_out, "Wrong impersonation level." );
|
|
ASSERT_EXPR( RPC_C_AUTHN_WINNT == authn_svc_out, "Wrong authentication service." );
|
|
ASSERT_EXPR( RPC_C_AUTHZ_NONE == authz_svc_out, "Wrong authorization service." );
|
|
}
|
|
|
|
// Query for the interface.
|
|
result = server->QueryInterface( iid, (void **) &test );
|
|
ASSERT( result, "Could not query interface" );
|
|
|
|
success = TRUE;
|
|
cleanup:
|
|
CoTaskMemFree( princ_name_out );
|
|
if (test != NULL)
|
|
test->Release();
|
|
return success;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL do_unknown_helper( IUnknown *server )
|
|
{
|
|
BOOL success;
|
|
|
|
// Make an unsecure impersonate query.
|
|
success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, IID_ITestNoneImp );
|
|
if (!success) return FALSE;
|
|
|
|
// Make a connect level impersonate query.
|
|
success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, IID_ITestConnectImp );
|
|
if (!success) return FALSE;
|
|
|
|
// Make an encrypt level impersonate query.
|
|
success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, IID_ITestEncryptImp );
|
|
if (!success) return FALSE;
|
|
|
|
// Make an unsecure identify query.
|
|
success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_NONE,
|
|
RPC_C_IMP_LEVEL_IDENTIFY, IID_ITestNoneId );
|
|
if (!success) return FALSE;
|
|
|
|
// Make a connect level identify query.
|
|
success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IDENTIFY, IID_ITestConnectId );
|
|
if (!success) return FALSE;
|
|
|
|
// Make an encrypt level identify query.
|
|
success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_IMP_LEVEL_IDENTIFY, IID_ITestEncryptId );
|
|
if (!success) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void *Fixup( char *name )
|
|
{
|
|
HINSTANCE ole;
|
|
void *fn;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return NULL;
|
|
}
|
|
|
|
// Get the function
|
|
fn = GetProcAddress( ole, name );
|
|
FreeLibrary( ole );
|
|
if (fn == NULL)
|
|
{
|
|
printf( "Could not find %s in ole32.dll.\n", name );
|
|
return NULL;
|
|
}
|
|
|
|
// Call function
|
|
return fn;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoCopyProxy(
|
|
IUnknown *pProxy,
|
|
IUnknown **ppCopy )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoCopyProxy = (CoCopyProxyFn) GetProcAddress( ole, "CoCopyProxy" );
|
|
FreeLibrary( ole );
|
|
if (GCoCopyProxy == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoCopyProxy( pProxy, ppCopy );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoGetCallContext( REFIID riid, void **ppInterface )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoGetCallContext = (CoGetCallContextFn)
|
|
GetProcAddress( ole, "CoGetCallContext" );
|
|
FreeLibrary( ole );
|
|
if (GCoGetCallContext == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoGetCallContext( riid, ppInterface );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoImpersonateClient()
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoImpersonateClient = (CoImpersonateClientFn)
|
|
GetProcAddress( ole, "CoImpersonateClient" );
|
|
FreeLibrary( ole );
|
|
if (GCoImpersonateClient == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoImpersonateClient();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoInitializeSecurity(
|
|
SECURITY_DESCRIPTOR *pSecDesc,
|
|
DWORD cAuthSvc,
|
|
SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
|
|
WCHAR *pPrincName,
|
|
DWORD dwAuthnLevel,
|
|
DWORD dwImpLevel,
|
|
RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
|
|
DWORD dwCapabilities,
|
|
void *pReserved )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoInitializeSecurity = (CoInitializeSecurityFn)
|
|
GetProcAddress( ole, "CoInitializeSecurity" );
|
|
FreeLibrary( ole );
|
|
if (GCoInitializeSecurity == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoInitializeSecurity( pSecDesc, cAuthSvc, asAuthSvc, pPrincName,
|
|
dwAuthnLevel, dwImpLevel, pAuthInfo,
|
|
dwCapabilities, pReserved );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoQueryAuthenticationServices( DWORD *pcbAuthSvc,
|
|
SOLE_AUTHENTICATION_SERVICE **asAuthSvc )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoQueryAuthenticationServices = (CoQueryAuthenticationServicesFn)
|
|
GetProcAddress( ole, "CoQueryAuthenticationServices" );
|
|
FreeLibrary( ole );
|
|
if (GCoQueryAuthenticationServices == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoQueryAuthenticationServices( pcbAuthSvc, asAuthSvc );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoQueryClientBlanket(
|
|
DWORD *pAuthnSvc,
|
|
DWORD *pAuthzSvc,
|
|
OLECHAR **pServerPrincName,
|
|
DWORD *pAuthnLevel,
|
|
DWORD *pImpLevel,
|
|
RPC_AUTHZ_HANDLE *pPrivs,
|
|
DWORD *pCapabilities )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoQueryClientBlanket = (CoQueryClientBlanketFn)
|
|
GetProcAddress( ole, "CoQueryClientBlanket" );
|
|
FreeLibrary( ole );
|
|
if (GCoQueryClientBlanket == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoQueryClientBlanket( pAuthnSvc, pAuthzSvc, pServerPrincName,
|
|
pAuthnLevel, pImpLevel, pPrivs, pCapabilities );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoQueryProxyBlanket(
|
|
IUnknown *pProxy,
|
|
DWORD *pAuthnSvc,
|
|
DWORD *pAuthzSvc,
|
|
OLECHAR **pServerPrincName,
|
|
DWORD *pAuthnLevel,
|
|
DWORD *pImpLevel,
|
|
RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
|
|
DWORD *pCapabilities )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoQueryProxyBlanket = (CoQueryProxyBlanketFn)
|
|
GetProcAddress( ole, "CoQueryProxyBlanket" );
|
|
FreeLibrary( ole );
|
|
if (GCoQueryProxyBlanket == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoQueryProxyBlanket( pProxy, pAuthnSvc, pAuthzSvc, pServerPrincName,
|
|
pAuthnLevel, pImpLevel, pAuthInfo, pCapabilities );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoRevertToSelf()
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoRevertToSelf = (CoRevertToSelfFn) GetProcAddress( ole, "CoRevertToSelf" );
|
|
FreeLibrary( ole );
|
|
if (GCoRevertToSelf == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoRevertToSelf();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoSetProxyBlanket(
|
|
IUnknown *pProxy,
|
|
DWORD dwAuthnSvc,
|
|
DWORD dwAuthzSvc,
|
|
OLECHAR *pServerPrincName,
|
|
DWORD dwAuthnLevel,
|
|
DWORD dwImpLevel,
|
|
RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
|
|
DWORD dwCapabilities )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoSetProxyBlanket = (CoSetProxyBlanketFn)
|
|
GetProcAddress( ole, "CoSetProxyBlanket" );
|
|
FreeLibrary( ole );
|
|
if (GCoSetProxyBlanket == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoSetProxyBlanket( pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName,
|
|
dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT __stdcall FixupCoSwitchCallContext( IUnknown *pNewObject, IUnknown **ppOldObject )
|
|
{
|
|
HINSTANCE ole;
|
|
HRESULT result;
|
|
|
|
// Load ole32.dll
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get security function.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get the function
|
|
GCoSwitchCallContext = (CoSwitchCallContextFn)
|
|
GetProcAddress( ole, "CoSwitchCallContext" );
|
|
FreeLibrary( ole );
|
|
if (GCoSwitchCallContext == NULL)
|
|
{
|
|
printf( "Could not find security in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call function
|
|
return GCoSwitchCallContext( pNewObject, ppOldObject );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD get_sequence()
|
|
{
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
return ProcessAptData.sequence++;
|
|
else
|
|
{
|
|
SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
|
|
return tls_data->sequence++;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void hello( char *test )
|
|
{
|
|
// Say hello.
|
|
if (ThreadMode == COINIT_SINGLETHREADED)
|
|
printf( "Running %s test in single threaded mode.\n", test );
|
|
else if (ThreadMode == COINIT_APARTMENTTHREADED)
|
|
printf( "Running %s test in apartment threaded mode.\n", test );
|
|
else
|
|
printf( "Running %s test in multithreaded mode.\n", test );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void increment_object_count()
|
|
{
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
InterlockedIncrement( &ProcessAptData.object_count );
|
|
ProcessAptData.what_next = wait_wn;
|
|
}
|
|
else
|
|
{
|
|
SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
|
|
tls_data->object_count += 1;
|
|
tls_data->what_next = wait_wn;
|
|
}
|
|
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT initialize( void *reserved, ULONG flags )
|
|
{
|
|
HINSTANCE ole;
|
|
INIT_FN init_ex;
|
|
HRESULT result;
|
|
|
|
// For the apartment model, just use CoInitialize.
|
|
if (flags == COINIT_APARTMENTTHREADED)
|
|
return CoInitialize( NULL );
|
|
|
|
// For free threading, try to find the CoInitializeEx API.
|
|
ole = LoadLibraryA( "ole32.dll" );
|
|
if (ole == NULL)
|
|
{
|
|
printf( "Could not load ole32.dll to get CoInitializeEx.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Get CoInitializeEx.
|
|
init_ex = (INIT_FN) GetProcAddress( ole, "CoInitializeEx" );
|
|
if (init_ex == NULL)
|
|
{
|
|
FreeLibrary( ole );
|
|
printf( "Could not find CoInitializeEx in ole32.dll.\n" );
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Call CoInitializeEx.
|
|
result = init_ex( reserved, flags );
|
|
FreeLibrary( ole );
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT initialize_security()
|
|
{
|
|
HRESULT result;
|
|
SOLE_AUTHENTICATION_SERVICE svc_list;
|
|
|
|
// Initialize security.
|
|
if (GlobalSecurityModel == basic_sm)
|
|
{
|
|
printf( "Basic security model.\n" );
|
|
svc_list.dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
svc_list.dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
svc_list.pPrincipalName = NULL;
|
|
result = MCoInitializeSecurity( NULL, 1, &svc_list, NULL, GlobalAuthnLevel,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
}
|
|
else if (GlobalSecurityModel == auto_sm)
|
|
{
|
|
printf( "Automatic security model.\n" );
|
|
result = MCoInitializeSecurity( NULL, -1, NULL, NULL, GlobalAuthnLevel,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
|
|
EOAC_NONE, NULL );
|
|
}
|
|
else
|
|
{
|
|
printf( "Legacy security model.\n" );
|
|
result = S_OK;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void interrupt()
|
|
{
|
|
while (GlobalInterruptTest)
|
|
{
|
|
GlobalTest->check( GlobalApt );
|
|
check_for_request();
|
|
}
|
|
GlobalTest->Release();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void interrupt_marshal()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_MARSHAL_LOOP; i++ )
|
|
{
|
|
GlobalTest->recurse( GlobalTest2, 1 );
|
|
check_for_request();
|
|
}
|
|
GlobalTest->Release();
|
|
GlobalTest2->Release();
|
|
what_next( wait_wn );
|
|
}
|
|
|
|
/***************************************************************************
|
|
Function: main
|
|
|
|
Synopsis: Executes the BasicBnd test
|
|
|
|
Effects: None
|
|
|
|
|
|
Returns: Exits with exit code 0 if success, 1 otherwise
|
|
|
|
***************************************************************************/
|
|
|
|
int _cdecl main(int argc, char *argv[])
|
|
{
|
|
HRESULT result;
|
|
SAptData tls_data;
|
|
BOOL success = TRUE;
|
|
DWORD ignore;
|
|
TOKEN_USER *token_info = NULL;
|
|
DWORD info_size = 1024;
|
|
HANDLE token = NULL;
|
|
|
|
// Initialize Globals.
|
|
MainThread = GetCurrentThreadId();
|
|
ignore = sizeof(Name);
|
|
GetComputerName( Name, &ignore );
|
|
|
|
// Create an event for termination notification.
|
|
Done = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
if (Done == NULL)
|
|
{
|
|
printf( "Could not create event.\n" );
|
|
return 0;
|
|
}
|
|
|
|
// Get an event for signalling raw RPCs.
|
|
RawEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
if (RawEvent == NULL)
|
|
{
|
|
printf( "Could not create event.\n" );
|
|
return 0;
|
|
}
|
|
|
|
// Allocate a TLS index.
|
|
TlsIndex = TlsAlloc();
|
|
if (TlsIndex == 0xffffffff)
|
|
{
|
|
printf( "Could not allocate TLS index.\n" );
|
|
return 0;
|
|
}
|
|
|
|
// Open the process's token.
|
|
OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token );
|
|
result = GetLastError();
|
|
if (result != 0)
|
|
{
|
|
printf( "Could not OpenProcessToken.\n" );
|
|
return 0;
|
|
}
|
|
|
|
// Lookup SID of process token.
|
|
token_info = (TOKEN_USER *) malloc( info_size );
|
|
if (token_info == NULL)
|
|
{
|
|
printf( "Could not allocate memory for token info.\n" );
|
|
return 0;
|
|
}
|
|
GetTokenInformation( token, TokenUser, token_info, info_size, &info_size );
|
|
result = GetLastError();
|
|
if (result != 0)
|
|
{
|
|
printf( "Could not GetTokenInformation.\n" );
|
|
return 0;
|
|
}
|
|
ProcessSid = (SID *) token_info->User.Sid;
|
|
CloseHandle( token );
|
|
|
|
// Parse the parameters.
|
|
if (!parse( argc, argv ))
|
|
return 0;
|
|
|
|
// Make sure the registry is set.
|
|
if (!registry_setup( argv[0] ))
|
|
return 0;
|
|
|
|
// Initiailize the apartment global data for the multithreaded mode.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
ProcessAptData.object_count = 0;
|
|
ProcessAptData.what_next = setup_wn;
|
|
ProcessAptData.exit_dirty = FALSE;
|
|
ProcessAptData.sequence = 0;
|
|
}
|
|
|
|
// In the single threaded mode, stick a pointer to the object count
|
|
// in TLS.
|
|
else
|
|
{
|
|
tls_data.object_count = 0;
|
|
tls_data.what_next = setup_wn;
|
|
tls_data.exit_dirty = FALSE;
|
|
tls_data.sequence = 0;
|
|
TlsSetValue( TlsIndex, &tls_data );
|
|
}
|
|
|
|
// Switch to the correct test.
|
|
switch_test();
|
|
|
|
// Cleanup.
|
|
TlsFree( TlsIndex );
|
|
CloseHandle( Done );
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
void __RPC_FAR * __RPC_API midl_user_allocate( size_t count )
|
|
{
|
|
return malloc(count);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
void __RPC_USER midl_user_free( void __RPC_FAR * p )
|
|
{
|
|
free( p );
|
|
}
|
|
|
|
/*************************************************************************/
|
|
HRESULT new_apartment_test( ITest ** test, SAptId *id, HANDLE *thread_out )
|
|
{
|
|
new_apt_params params;
|
|
HANDLE thread;
|
|
DWORD thread_id;
|
|
DWORD status;
|
|
HRESULT result;
|
|
IClassFactory *factory;
|
|
|
|
// Create an event.
|
|
params.stream = NULL;
|
|
params.ready = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
if (params.ready == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Start a new thread/apartment.
|
|
thread = CreateThread( NULL, 0, apartment_base, ¶ms, 0, &thread_id );
|
|
if (thread == NULL)
|
|
{
|
|
result = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Wait till it has marshalled a class factory.
|
|
status = WaitForSingleObject( params.ready, INFINITE );
|
|
if (status != WAIT_OBJECT_0 || params.stream == NULL)
|
|
{
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Unmarshal the class factory.
|
|
result = CoUnmarshalInterface( params.stream, IID_IClassFactory,
|
|
(void **) &factory );
|
|
params.stream->Release();
|
|
if (FAILED(result))
|
|
goto cleanup;
|
|
|
|
// Create a test object.
|
|
result = factory->CreateInstance( NULL, IID_ITest, (void **) test );
|
|
factory->Release();
|
|
if (*test != NULL)
|
|
(*test)->get_id( id );
|
|
|
|
cleanup:
|
|
if (thread_out != NULL && SUCCEEDED(result))
|
|
*thread_out = thread;
|
|
else
|
|
CloseHandle( thread );
|
|
if (params.ready != NULL)
|
|
CloseHandle( params.ready );
|
|
return result;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/* Parse the arguments. */
|
|
BOOL parse( int argc, char *argv[] )
|
|
{
|
|
int i;
|
|
int len;
|
|
char buffer[80];
|
|
|
|
WhatTest = lots_wt;
|
|
ThreadMode = COINIT_APARTMENTTHREADED;
|
|
|
|
// Parse each item, skip the command name
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (_stricmp( argv[i], "Apartment" ) == 0)
|
|
ThreadMode = COINIT_APARTMENTTHREADED;
|
|
|
|
else if (_stricmp( argv[i], "-auto" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include an authentication level after the -auto option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &GlobalAuthnLevel );
|
|
GlobalSecurityModel = auto_sm;
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "-b" ) == 0)
|
|
DebugBreak();
|
|
|
|
else if (_stricmp( argv[i], "-basic" ) == 0)
|
|
GlobalSecurityModel = basic_sm;
|
|
|
|
else if (_stricmp( argv[i], "-c" ) == 0)
|
|
Change = TRUE;
|
|
|
|
else if (_stricmp( argv[i], "Cancel" ) == 0)
|
|
WhatTest = cancel_wt;
|
|
|
|
else if (_stricmp( argv[i], "Crash" ) == 0)
|
|
WhatTest = crash_wt;
|
|
|
|
else if (_stricmp( argv[i], "Cstress" ) == 0)
|
|
WhatTest = cstress_wt;
|
|
|
|
else if (_stricmp( argv[i], "-d" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include a debugger after the -d option.\n" );
|
|
return FALSE;
|
|
}
|
|
WriteClass = TRUE;
|
|
if (_stricmp( argv[i], "none" ) == 0)
|
|
strcpy( Debugger, "" );
|
|
// MultiByteToWideChar( CP_ACP, 0, "", 0, Debugger, sizeof(Debugger) );
|
|
else
|
|
strcpy( Debugger, argv[i] );
|
|
// MultiByteToWideChar( CP_ACP, 0, argv[i], strlen(argv[i], Debugger,
|
|
// sizeof(Debugger) );
|
|
if (WhatTest = lots_wt)
|
|
WhatTest = none_wt;
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "-Embedding" ) == 0)
|
|
WhatTest = server_wt;
|
|
|
|
else if (_stricmp( argv[i], "-i" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include an iteration count after the -i option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &NumIterations );
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "Hook" ) == 0)
|
|
WhatTest = hook_wt;
|
|
|
|
else if (_stricmp( argv[i], "-legacy" ) == 0)
|
|
GlobalSecurityModel = legacy_sm;
|
|
|
|
else if (_stricmp( argv[i], "load_client" ) == 0)
|
|
WhatTest = load_client_wt;
|
|
|
|
else if (_stricmp( argv[i], "Load_Server" ) == 0)
|
|
WhatTest = load_server_wt;
|
|
|
|
else if (_stricmp( argv[i], "Mmarshal" ) == 0)
|
|
WhatTest = mmarshal_wt;
|
|
|
|
else if (_stricmp( argv[i], "Multi" ) == 0)
|
|
ThreadMode = COINIT_MULTITHREADED;
|
|
|
|
else if (_stricmp( argv[i], "-n" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include a name after the -n option.\n" );
|
|
return FALSE;
|
|
}
|
|
MultiByteToWideChar( CP_ACP, 0, argv[i], strlen(argv[i]), Name,
|
|
sizeof(Name) );
|
|
Name[strlen(argv[i])] = 0;
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "Null" ) == 0)
|
|
WhatTest = null_wt;
|
|
|
|
else if (_stricmp( argv[i], "One" ) == 0)
|
|
WhatTest = one_wt;
|
|
|
|
else if (_stricmp( argv[i], "Perf" ) == 0)
|
|
WhatTest = perf_wt;
|
|
|
|
else if (_stricmp( argv[i], "PerfRemote" ) == 0)
|
|
WhatTest = perfremote_wt;
|
|
|
|
else if (_stricmp( argv[i], "PerfRpc" ) == 0)
|
|
WhatTest = perfrpc_wt;
|
|
|
|
else if (_stricmp( argv[i], "PerfSec" ) == 0)
|
|
WhatTest = perfsec_wt;
|
|
|
|
else if (_stricmp( argv[i], "Post" ) == 0)
|
|
WhatTest = post_wt;
|
|
|
|
else if (_stricmp( argv[i], "-o" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include an object count after the -o option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &NumObjects );
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "-o" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include an object count after the -o option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &NumObjects );
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "-p" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include a process count after the -p option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &NumProcesses );
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "-popup" ) == 0)
|
|
Popup = TRUE;
|
|
|
|
else if (_stricmp( argv[i], "-r" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include a recursion count after the -r option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &NumRecursion );
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "Reject" ) == 0)
|
|
WhatTest = reject_wt;
|
|
|
|
else if (_stricmp( argv[i], "Remote_client" ) == 0)
|
|
WhatTest = remote_client_wt;
|
|
|
|
else if (_stricmp( argv[i], "Remote_server" ) == 0)
|
|
WhatTest = remote_server_wt;
|
|
|
|
else if (_stricmp( argv[i], "Ring" ) == 0)
|
|
WhatTest = ring_wt;
|
|
|
|
else if (_stricmp( argv[i], "Rpc" ) == 0)
|
|
WhatTest = rpc_wt;
|
|
|
|
else if (_stricmp( argv[i], "Rundown" ) == 0)
|
|
WhatTest = rundown_wt;
|
|
|
|
else if (_stricmp( argv[i], "-s" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include a protocol sequence after the -s option.\n" );
|
|
return FALSE;
|
|
}
|
|
MultiByteToWideChar( CP_ACP, 0, argv[i], strlen(argv[i]), TestProtseq,
|
|
sizeof(TestProtseq) );
|
|
TestProtseq[strlen(argv[i])] = 0;
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "Security" ) == 0)
|
|
WhatTest = security_wt;
|
|
|
|
else if (_stricmp( argv[i], "SecureRefs" ) == 0)
|
|
WhatTest = securerefs_wt;
|
|
|
|
else if (_stricmp( argv[i], "Send" ) == 0)
|
|
WhatTest = send_wt;
|
|
|
|
else if (_stricmp( argv[i], "-t" ) == 0)
|
|
{
|
|
if (argv[++i] == NULL)
|
|
{
|
|
printf( "You must include a thread count after the -t option.\n" );
|
|
return FALSE;
|
|
}
|
|
sscanf( argv[i], "%d", &NumThreads );
|
|
}
|
|
|
|
else if (_stricmp( argv[i], "sid" ) == 0)
|
|
WhatTest = sid_wt;
|
|
|
|
else if (_stricmp( argv[i], "Simple_rundown" ) == 0)
|
|
WhatTest = simple_rundown_wt;
|
|
|
|
else if (_stricmp( argv[i], "Thread" ) == 0)
|
|
WhatTest = thread_wt;
|
|
|
|
else if (_stricmp( argv[i], "Three" ) == 0)
|
|
WhatTest = three_wt;
|
|
|
|
else if (_stricmp( argv[i], "Two" ) == 0)
|
|
WhatTest = two_wt;
|
|
|
|
else if (_stricmp( argv[i], "Uninit" ) == 0)
|
|
WhatTest = uninit_wt;
|
|
|
|
else if (_stricmp( argv[i], "Unknown" ) == 0)
|
|
WhatTest = unknown_wt;
|
|
|
|
else
|
|
{
|
|
printf( "You don't know what you are doing!\n" );
|
|
printf( "This program tests the channel.\n" );
|
|
printf( "\n" );
|
|
printf( "Apartment Apartment threading mode.\n" );
|
|
printf( "Cancel Cancel test.\n" );
|
|
printf( "Crash Crash test.\n" );
|
|
printf( "Cstress Cancel stress test.\n" );
|
|
printf( "Hook Channel hook test.\n" );
|
|
printf( "Load_Client Remote load performance - client.\n" );
|
|
printf( "Load_Server Remote load performance - server.\n" );
|
|
printf( "Mmarshal Multiple marshal test.\n" );
|
|
printf( "Multi Multithreaded mode.\n" );
|
|
printf( "Null Apartment null call test.\n" );
|
|
printf( "One Used for testing new tests.\n" );
|
|
printf( "Perf Performance test.\n" );
|
|
printf( "PerfRemote Remote call performance test.\n" );
|
|
printf( "PerfRpc Raw RPC performance test.\n" );
|
|
printf( "PerfSec Security performance test.\n" );
|
|
printf( "Post Post a message to window specified by -i.\n" );
|
|
printf( "Reject Reject test.\n" );
|
|
printf( "Remote_Client Remote performance - client.\n" );
|
|
printf( "Remote_Server Remote performance - server.\n" );
|
|
printf( "Ring Run ring test.\n" );
|
|
printf( "Rpc Test both RPC and OLE calls.\n" );
|
|
printf( "Rundown Rundown test.\n" );
|
|
printf( "SecureRefs Secure Addref/Release Test.\n" );
|
|
printf( "Security Security test.\n" );
|
|
printf( "Send Send a message to window specified by -i.\n" );
|
|
printf( "Sid Lookup the sid for the name specified by -n\n" );
|
|
printf( "Simple_Rundown Wait for object exporter to timeout.\n" );
|
|
printf( "Thread Calling on multiple threads.\n" );
|
|
printf( "Three Used for reproducing bugs.\n" );
|
|
printf( "Two Used for reproducing bugs.\n" );
|
|
printf( "Uninit Calls during uninitialization.\n" );
|
|
printf( "Unknown IUnknown security.\n" );
|
|
printf( "\n" );
|
|
printf( "-auto n Use automatic security set to level n.\n" );
|
|
printf( "-b Stop in debugger before going on.\n" );
|
|
printf( "-basic Use basic security.\n" );
|
|
printf( "-c Change the test.\n" );
|
|
printf( "-d debugger Debugger to run app under of none.\n" );
|
|
printf( "-Embedding Server side.\n" );
|
|
printf( "-legacy Use legacy security.\n" );
|
|
printf( "-i n Number of iterations.\n" );
|
|
printf( "-n name String name.\n" );
|
|
printf( "-o n Number of objects.\n" );
|
|
printf( "-p n Number of processes.\n" );
|
|
printf( "-popup Display popups for sync during test.\n" );
|
|
printf( "-r n Number of recursions.\n" );
|
|
printf( "-s protseq Change default protocol sequence.\n" );
|
|
printf( "-t n Number of threads.\n" );
|
|
printf( "\n" );
|
|
printf( "The test currently only runs in the single threaded mode\n" );
|
|
printf( "and requires the apartment model.\n" );
|
|
printf( "If no test is specified the cancel, crash, null,\n" );
|
|
printf( "ring, and rundown tests will be run. The options have the\n" );
|
|
printf( "following default values.\n" );
|
|
printf( " authn level - %d\n", GlobalAuthnLevel );
|
|
printf( " iterations - 1000\n" );
|
|
printf( " name - %ws\n", Name );
|
|
printf( " objects - 2\n" );
|
|
printf( " processes - 2\n" );
|
|
printf( " recurse - 2\n" );
|
|
printf( " protseq - %ws\n", TestProtseq );
|
|
printf( " security model - %d\n", GlobalSecurityModel );
|
|
printf( " threads - 2\n" );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Figure out the class id based on the thread model and security model.
|
|
if (GlobalSecurityModel == auto_sm)
|
|
if (GlobalAuthnLevel == RPC_C_AUTHN_LEVEL_CONNECT)
|
|
i = 1;
|
|
else if (GlobalAuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
|
i = 2;
|
|
else
|
|
i = 0;
|
|
else if (GlobalSecurityModel == basic_sm)
|
|
i = 3;
|
|
else
|
|
i = 4;
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
ServerClsid = &ClassIds[free_auto_none+i];
|
|
else
|
|
ServerClsid = &ClassIds[apt_auto_none+i];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
BOOL registry_setup( char *argv0 )
|
|
{
|
|
char value[REGISTRY_ENTRY_LEN];
|
|
LONG value_size;
|
|
LONG result;
|
|
char directory[MAX_PATH];
|
|
char *appname;
|
|
int i;
|
|
int j;
|
|
char *class_id;
|
|
HKEY key = NULL;
|
|
DWORD ignore;
|
|
SECURITY_DESCRIPTOR *sec;
|
|
|
|
// Find out if the registry is setup.
|
|
value_size = sizeof(value);
|
|
result = RegQueryValueA(
|
|
HKEY_CLASSES_ROOT,
|
|
REG_CLASS_EXE,
|
|
value,
|
|
&value_size );
|
|
|
|
// If the registry is not setup or needs to be rewritten, write it.
|
|
if (result != ERROR_SUCCESS || WriteClass)
|
|
{
|
|
// Write all the interface ids.
|
|
for (i = 0; i < NUM_INTERFACE_IDS; i++)
|
|
{
|
|
// Write the interface name.
|
|
strcpy( value, "Interface\\{60000200-76d7-11cf-9af1-0020af6e72f4}" );
|
|
value[18] += i;
|
|
result = RegSetValueA(
|
|
HKEY_CLASSES_ROOT,
|
|
value,
|
|
REG_SZ,
|
|
REG_INTERFACE_NAME[i],
|
|
strlen(REG_INTERFACE_NAME[i]) );
|
|
ASSERT( result, "Could not set interface name: 0x%x" );
|
|
|
|
// Write the interface to proxy class id translation.
|
|
strcpy( value, "Interface\\{60000200-76d7-11cf-9af1-0020af6e72f4}\\ProxyStubClsid32" );
|
|
value[18] += i;
|
|
result = RegSetValueA(
|
|
HKEY_CLASSES_ROOT,
|
|
value,
|
|
REG_SZ,
|
|
REG_INTERFACE_CLASS,
|
|
strlen(REG_INTERFACE_CLASS) );
|
|
ASSERT( result, "Could not set interface class: 0x%x" );
|
|
}
|
|
|
|
// Write the proxy name.
|
|
result = RegSetValueA(
|
|
HKEY_CLASSES_ROOT,
|
|
"CLSID\\{60000200-76d7-11cf-9af1-0020af6e72f4}",
|
|
REG_SZ,
|
|
REG_PROXY_NAME,
|
|
strlen(REG_PROXY_NAME) );
|
|
ASSERT( result, "Could not set interface name: 0x%x" );
|
|
|
|
// Compute the path to the application.
|
|
result = GetFullPathNameA( argv0, sizeof(directory), directory, &appname );
|
|
ASSERT_EXPR( result != 0, "Could not GetFullPathName." );
|
|
result = appname - directory;
|
|
if (result + strlen(REG_PROXY_DLL) > MAX_PATH ||
|
|
result + strlen(REG_APP_EXE) + strlen(Debugger) > MAX_PATH)
|
|
{
|
|
printf( "Buffer too small.\n" );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Write the proxy dll path.
|
|
strcpy( appname, REG_PROXY_DLL );
|
|
result = RegSetValueA(
|
|
HKEY_CLASSES_ROOT,
|
|
"CLSID\\{60000200-76d7-11cf-9af1-0020af6e72f4}\\InprocServer32",
|
|
REG_SZ,
|
|
directory,
|
|
strlen(directory) );
|
|
ASSERT( result, "Could not set interface name: 0x%x" );
|
|
|
|
// Open the registry key for the app id.
|
|
result = RegCreateKeyExA( HKEY_CLASSES_ROOT,
|
|
"AppID\\{60000200-76d7-11cf-9af1-0020af6e72f4}",
|
|
NULL,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&key,
|
|
&ignore );
|
|
ASSERT( result, "Could not create app id key: 0x%x" );
|
|
|
|
// Write the app id.
|
|
result = RegSetValueExA(
|
|
key,
|
|
NULL,
|
|
NULL,
|
|
REG_SZ,
|
|
(UCHAR *) REG_APPID_NAME,
|
|
strlen(REG_APPID_NAME) );
|
|
ASSERT( result, "Could not set app id name: 0x%x" );
|
|
|
|
// Make a simple security descriptor allowing everyone access.
|
|
i = GetLengthSid( ProcessSid );
|
|
sec = (SECURITY_DESCRIPTOR *) CoTaskMemAlloc( sizeof(SECURITY_DESCRIPTOR) +
|
|
i*2 );
|
|
ASSERT_EXPR( sec != NULL, "Could not allocate memory." );
|
|
sec->Revision = SECURITY_DESCRIPTOR_REVISION;
|
|
sec->Sbz1 = 0;
|
|
sec->Control = SE_SELF_RELATIVE;
|
|
sec->Owner = (SID *) sizeof(SECURITY_DESCRIPTOR);
|
|
sec->Group = (SID *) (sizeof(SECURITY_DESCRIPTOR) + i);
|
|
sec->Sacl = NULL;
|
|
sec->Dacl = NULL;
|
|
memcpy( sec+1, ProcessSid, i );
|
|
memcpy( ((char *) (sec+1)) + i, ProcessSid, i );
|
|
|
|
// Write the launch permissions.
|
|
result = RegSetValueExA(
|
|
key,
|
|
"LaunchPermission",
|
|
NULL,
|
|
REG_BINARY,
|
|
(UCHAR *) sec,
|
|
sizeof(SECURITY_DESCRIPTOR) + 2*i );
|
|
ASSERT( result, "Could not set launch permissions: 0x%x" );
|
|
|
|
// Write the access permissions.
|
|
result = RegSetValueExA(
|
|
key,
|
|
"AccessPermission",
|
|
NULL,
|
|
REG_BINARY,
|
|
(UCHAR *) sec,
|
|
sizeof(SECURITY_DESCRIPTOR) + 2*i );
|
|
ASSERT( result, "Could not set access permissions: 0x%x" );
|
|
|
|
// Write the value to run as logged on user.
|
|
result = RegSetValueExA(
|
|
key,
|
|
"RunAs",
|
|
NULL,
|
|
REG_SZ,
|
|
(unsigned char *) REG_LOGGED_ON,
|
|
strlen(REG_LOGGED_ON) );
|
|
ASSERT( result, "Could not set RunAs value: 0x%x" );
|
|
RegCloseKey( key );
|
|
key = NULL;
|
|
|
|
// Open the registry key for the module name.
|
|
result = RegCreateKeyExA( HKEY_CLASSES_ROOT,
|
|
"AppID\\app.exe",
|
|
NULL,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&key,
|
|
&ignore );
|
|
ASSERT( result, "Could not create module name key: 0x%x" );
|
|
|
|
// Write the app id under the module name.
|
|
result = RegSetValueExA(
|
|
key,
|
|
"AppID",
|
|
NULL,
|
|
REG_SZ,
|
|
(unsigned char *) REG_INTERFACE_CLASS,
|
|
strlen(REG_INTERFACE_CLASS) );
|
|
ASSERT( result, "Could not set appid value: 0x%x" );
|
|
RegCloseKey( key );
|
|
key = NULL;
|
|
|
|
// Compute the base application execution command.
|
|
strcpy( appname, REG_APP_EXE );
|
|
i = strlen( Debugger );
|
|
if (i != 0)
|
|
Debugger[i++] = ' ';
|
|
strcpy( &Debugger[i], directory );
|
|
i = strlen( Debugger );
|
|
|
|
// Allocate strings for the class id name keys.
|
|
class_id = (char *) _alloca( strlen(REG_CLASS_ID) + 1 );
|
|
if (class_id == NULL)
|
|
{
|
|
printf( "Could not _alloca string space.\n" );
|
|
return FALSE;
|
|
}
|
|
strcpy( class_id, REG_CLASS_ID );
|
|
|
|
// Write all the class ids.
|
|
for (j = 0; j < NUM_CLASS_IDS; j++)
|
|
{
|
|
// Adjust the id in the class strings.
|
|
class_id[14] = '0'+j;
|
|
|
|
// Open the registry key for the app id.
|
|
result = RegCreateKeyExA( HKEY_CLASSES_ROOT,
|
|
class_id,
|
|
NULL,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&key,
|
|
&ignore );
|
|
ASSERT( result, "Could not create class id key: 0x%x" );
|
|
|
|
// Write the application class name for the apartment class.
|
|
result = RegSetValueExA(
|
|
key,
|
|
NULL,
|
|
NULL,
|
|
REG_SZ,
|
|
(UCHAR *) REG_APP_NAME[j],
|
|
strlen(REG_APP_NAME[j]) );
|
|
ASSERT( result, "Could not set interface name: 0x%x" );
|
|
|
|
// Write the application path.
|
|
strcpy( &Debugger[i], REG_APP_OPTIONS[j] );
|
|
result = RegSetValueA(
|
|
key,
|
|
"LocalServer32",
|
|
REG_SZ,
|
|
Debugger,
|
|
strlen(Debugger) );
|
|
ASSERT( result, "Could not set app exe: 0x%x" );
|
|
|
|
// Write the application id value.
|
|
result = RegSetValueExA(
|
|
key,
|
|
"AppID",
|
|
NULL,
|
|
REG_SZ,
|
|
(unsigned char *) REG_INTERFACE_CLASS,
|
|
strlen(REG_INTERFACE_CLASS) );
|
|
ASSERT( result, "Could not set appid value: 0x%x" );
|
|
RegCloseKey( key );
|
|
key = NULL;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
cleanup:
|
|
if (key != NULL)
|
|
RegCloseKey( key );
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void reinitialize()
|
|
{
|
|
HRESULT result;
|
|
SAptData *mine;
|
|
|
|
// Get the apartment specific data.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
mine = &ProcessAptData;
|
|
else
|
|
mine = (SAptData *) TlsGetValue( TlsIndex );
|
|
mine->what_next = quit_wn;
|
|
|
|
// Revoke the class factory.
|
|
ClassFactory->AddRef();
|
|
result = CoRevokeClassObject(Registration);
|
|
if (!SUCCEEDED(result))
|
|
{
|
|
printf( "CoRevokeClassObject failed: %x\n", result );
|
|
return;
|
|
}
|
|
|
|
// Reinitialize.
|
|
CoUninitialize();
|
|
result = initialize(NULL,ThreadMode);
|
|
if (!SUCCEEDED(result))
|
|
{
|
|
printf( "Could not reinitialize server: 0x%x\n", result );
|
|
return;
|
|
}
|
|
|
|
// Register our class with OLE
|
|
result = CoRegisterClassObject(*ServerClsid, ClassFactory, CLSCTX_LOCAL_SERVER,
|
|
REGCLS_SINGLEUSE, &Registration);
|
|
if (!SUCCEEDED(result))
|
|
{
|
|
printf( "CoRegisterClassObject failed: %x\n", result );
|
|
return;
|
|
}
|
|
|
|
// Make the server loop think we've started over.
|
|
mine->what_next = setup_wn;
|
|
mine->object_count = 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void server_loop( )
|
|
{
|
|
register SAptData *mine;
|
|
|
|
// Get the apartment specific data.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
mine = &ProcessAptData;
|
|
else
|
|
mine = (SAptData *) TlsGetValue( TlsIndex );
|
|
|
|
// Do whatever we have to do till it is time to pay our taxes and die.
|
|
while ((mine->what_next == setup_wn || mine->object_count > 0) &&
|
|
mine->what_next != quit_wn)
|
|
switch (mine->what_next)
|
|
{
|
|
|
|
// Wait till a quit arrives.
|
|
case setup_wn:
|
|
case wait_wn:
|
|
wait_for_message();
|
|
break;
|
|
|
|
case callback_wn:
|
|
callback();
|
|
mine->what_next = wait_wn;
|
|
break;
|
|
|
|
case catch_wn:
|
|
__try
|
|
{
|
|
mine->what_next = wait_wn;
|
|
server_loop();
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
printf( "Caught exception at top of thread 0x%x\n",
|
|
GetCurrentThreadId() );
|
|
mine->what_next = crippled_wn;
|
|
}
|
|
break;
|
|
|
|
case crippled_wn:
|
|
crippled();
|
|
break;
|
|
|
|
case interrupt_wn:
|
|
interrupt();
|
|
break;
|
|
|
|
case interrupt_marshal_wn:
|
|
interrupt_marshal();
|
|
break;
|
|
|
|
case reinitialize_wn:
|
|
reinitialize();
|
|
break;
|
|
|
|
case rest_and_die_wn:
|
|
Sleep(5000);
|
|
mine->what_next = quit_wn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
void switch_test()
|
|
{
|
|
switch (WhatTest)
|
|
{
|
|
case cancel_wt:
|
|
do_cancel();
|
|
break;
|
|
|
|
case crash_wt:
|
|
do_crash();
|
|
break;
|
|
|
|
case cstress_wt:
|
|
do_cstress();
|
|
break;
|
|
|
|
case hook_wt:
|
|
do_hook();
|
|
break;
|
|
|
|
case load_client_wt:
|
|
do_load_client();
|
|
break;
|
|
|
|
case load_server_wt:
|
|
do_load_server();
|
|
break;
|
|
|
|
case lots_wt:
|
|
do_lots();
|
|
break;
|
|
|
|
case mmarshal_wt:
|
|
do_mmarshal();
|
|
break;
|
|
|
|
case none_wt:
|
|
break;
|
|
|
|
case null_wt:
|
|
do_null();
|
|
break;
|
|
|
|
case one_wt:
|
|
do_one();
|
|
break;
|
|
|
|
case perf_wt:
|
|
do_perf();
|
|
break;
|
|
|
|
case perfremote_wt:
|
|
do_perfremote();
|
|
break;
|
|
|
|
case perfrpc_wt:
|
|
do_perfrpc();
|
|
break;
|
|
|
|
case perfsec_wt:
|
|
do_perfsec();
|
|
break;
|
|
|
|
case post_wt:
|
|
do_post();
|
|
break;
|
|
|
|
case reject_wt:
|
|
do_reject();
|
|
break;
|
|
|
|
case remote_client_wt:
|
|
do_remote_client();
|
|
break;
|
|
|
|
case remote_server_wt:
|
|
do_remote_server();
|
|
break;
|
|
|
|
case ring_wt:
|
|
do_ring();
|
|
break;
|
|
|
|
case rpc_wt:
|
|
do_rpc();
|
|
break;
|
|
|
|
case rundown_wt:
|
|
do_rundown();
|
|
break;
|
|
|
|
case securerefs_wt:
|
|
do_securerefs();
|
|
break;
|
|
|
|
case security_wt:
|
|
do_security();
|
|
break;
|
|
|
|
case send_wt:
|
|
do_send();
|
|
break;
|
|
|
|
case server_wt:
|
|
do_server();
|
|
break;
|
|
|
|
case sid_wt:
|
|
do_sid();
|
|
break;
|
|
|
|
case simple_rundown_wt:
|
|
do_simple_rundown();
|
|
break;
|
|
|
|
case thread_wt:
|
|
do_thread();
|
|
break;
|
|
|
|
case three_wt:
|
|
do_three();
|
|
break;
|
|
|
|
case two_wt:
|
|
do_two();
|
|
break;
|
|
|
|
case uninit_wt:
|
|
do_uninit();
|
|
break;
|
|
|
|
case unknown_wt:
|
|
do_unknown();
|
|
break;
|
|
|
|
default:
|
|
printf( "I don't know what to do - %d\n", WhatTest );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD _stdcall thread_helper( void *param )
|
|
{
|
|
ITest *test = (ITest *) param;
|
|
HRESULT result;
|
|
|
|
// Call the server.
|
|
result = test->sleep( 2000 );
|
|
|
|
// Check the result for multithreaded mode.
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
if (result != S_OK)
|
|
{
|
|
printf( "Could not make multiple calls in multithreaded mode: 0x%x\n",
|
|
result );
|
|
Multicall_Test = FALSE;
|
|
}
|
|
}
|
|
|
|
// Check the result for single threaded mode.
|
|
else
|
|
{
|
|
if (SUCCEEDED(result))
|
|
{
|
|
Multicall_Test = FALSE;
|
|
printf( "Call succeeded on wrong thread in single threaded mode: 0x%x.\n",
|
|
result );
|
|
}
|
|
#if NEVER
|
|
else if (DebugCoGetRpcFault() != RPC_E_ATTEMPTED_MULTITHREAD)
|
|
{
|
|
printf( "Multithread failure code was 0x%x not 0x%x\n",
|
|
DebugCoGetRpcFault(), RPC_E_ATTEMPTED_MULTITHREAD );
|
|
Multicall_Test = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#define DO_DA 42
|
|
return DO_DA;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
DWORD _stdcall status_helper( void *param )
|
|
{
|
|
long num_calls;
|
|
long num_clients;
|
|
long total_clients;
|
|
DWORD last_time;
|
|
DWORD this_time;
|
|
DWORD rate;
|
|
|
|
// Wake up periodically and print statistics.
|
|
last_time = GetTickCount();
|
|
while (TRUE)
|
|
{
|
|
Sleep( STATUS_DELAY );
|
|
num_calls = InterlockedExchange( &GlobalCalls, 0 );
|
|
num_clients = GlobalClients;
|
|
total_clients = GlobalTotal;
|
|
this_time = GetTickCount();
|
|
if (num_calls != 0)
|
|
rate = (this_time - last_time)*1000/num_calls;
|
|
else
|
|
rate = 99999999;
|
|
printf( "Time: %d Calls: %d Clients: %d Total Clients: %d uSec/Call: %d\n",
|
|
this_time - last_time, num_calls, num_clients, total_clients,
|
|
rate );
|
|
last_time = this_time;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
HRESULT switch_thread( SIMPLE_FN fn, void *param )
|
|
{
|
|
MSG msg;
|
|
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
fn( param );
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
if (PostThreadMessage( GlobalThreadId, WM_USER+1, (unsigned int) fn,
|
|
(long) param ))
|
|
{
|
|
GetMessage( &msg, NULL, 0, 0 );
|
|
return S_OK;
|
|
}
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void thread_get_interface_buffer( void *p )
|
|
{
|
|
SGetInterface *getif = (SGetInterface *) p;
|
|
HANDLE memory = NULL;
|
|
IStream *stream = NULL;
|
|
LARGE_INTEGER pos;
|
|
DWORD size;
|
|
void *objref;
|
|
WCHAR name[MAX_COMPUTERNAME_LENGTH+1];
|
|
DWORD name_size = sizeof(name)/sizeof(WCHAR);
|
|
|
|
// Find out how much memory to allocate.
|
|
getif->status = RPC_S_OUT_OF_RESOURCES;
|
|
getif->status = CoGetMarshalSizeMax( (unsigned long *) getif->buf_size,
|
|
IID_ITest, GlobalTest,
|
|
MSHCTX_DIFFERENTMACHINE,
|
|
NULL,
|
|
MSHLFLAGS_NORMAL );
|
|
ASSERT( getif->status, "Could not marshal server object" );
|
|
|
|
// Add the size of the long form extension.
|
|
ASSERT_EXPR( GetComputerName( name, &name_size ), "Could not get computer name." );
|
|
*getif->buf_size += 20 + 2*name_size*sizeof(WCHAR);
|
|
|
|
// Allocate memory.
|
|
memory = GlobalAlloc( GMEM_FIXED, *getif->buf_size );
|
|
ASSERT_EXPR( memory != NULL, "Could not allocate memory." );
|
|
|
|
// Create a stream.
|
|
getif->status = CreateStreamOnHGlobal( memory, TRUE, &stream );
|
|
ASSERT( getif->status, "Could not create stream" );
|
|
|
|
// Marshal the object.
|
|
getif->status = CoMarshalInterface( stream, IID_ITest, GlobalTest,
|
|
MSHCTX_DIFFERENTMACHINE,
|
|
NULL,
|
|
MSHLFLAGS_NORMAL );
|
|
ASSERT( getif->status, "Could not marshal object" );
|
|
|
|
// Find the object reference in the stream.
|
|
objref = (void *) GlobalLock( memory );
|
|
|
|
// Allocate a buffer for MIDL.
|
|
*getif->buffer = (unsigned char *) midl_user_allocate( *getif->buf_size );
|
|
ASSERT_EXPR( *getif->buffer != NULL, "Could not allocate MIDL memory." );
|
|
|
|
// Copy the stream to the buffer.
|
|
memcpy( *getif->buffer, objref, *getif->buf_size );
|
|
GlobalUnlock( memory );
|
|
|
|
// Make sure that the original reference to the object gets released once.
|
|
if (InterlockedExchange( &GlobalFirst, FALSE ) == TRUE)
|
|
GlobalTest->Release();
|
|
|
|
// Return the buffer.
|
|
getif->status = RPC_S_OK;
|
|
cleanup:
|
|
if (stream != NULL)
|
|
stream->Release();
|
|
PostThreadMessage( getif->thread, WM_USER, 0, 0 );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void __RPC_USER transmit_crash_to_xmit( transmit_crash __RPC_FAR *c, DWORD __RPC_FAR * __RPC_FAR *x )
|
|
{
|
|
|
|
*x = (DWORD *) CoTaskMemAlloc( 4 );
|
|
**x = 1 / *c;
|
|
*c -= 1;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void __RPC_USER transmit_crash_from_xmit( DWORD __RPC_FAR *x, transmit_crash __RPC_FAR *c )
|
|
{
|
|
*c = *x;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void __RPC_USER transmit_crash_free_inst( transmit_crash __RPC_FAR *x )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void __RPC_USER transmit_crash_free_xmit( DWORD __RPC_FAR *x )
|
|
{
|
|
CoTaskMemFree( x );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void wait_for_message()
|
|
{
|
|
MSG msg;
|
|
DWORD status;
|
|
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
status = WaitForSingleObject( Done, INFINITE );
|
|
if (status != WAIT_OBJECT_0 )
|
|
{
|
|
printf( "Could not wait for event.\n" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetMessageA( &msg, NULL, 0, 0 ))
|
|
{
|
|
if (msg.hwnd == NULL && msg.message == WM_USER+1)
|
|
((SIMPLE_FN) msg.wParam)( (void *) msg.lParam );
|
|
else
|
|
{
|
|
TranslateMessage (&msg);
|
|
DispatchMessageA (&msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void wake_up_and_smell_the_roses()
|
|
{
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
SetEvent( Done );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void what_next( what_next_en what )
|
|
{
|
|
if (ThreadMode == COINIT_MULTITHREADED)
|
|
{
|
|
ProcessAptData.what_next = what;
|
|
}
|
|
else
|
|
{
|
|
SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
|
|
tls_data->what_next = what;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
unsigned long xacl_call( handle_t binding )
|
|
{
|
|
RPC_STATUS status;
|
|
RPC_STATUS status2;
|
|
BOOL success;
|
|
DWORD granted_access;
|
|
BOOL access;
|
|
BOOL ignore;
|
|
HANDLE token;
|
|
PRIVILEGE_SET privilege;
|
|
DWORD privilege_size = sizeof(privilege);
|
|
GENERIC_MAPPING gmap;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER impersonate;
|
|
LARGE_INTEGER open;
|
|
LARGE_INTEGER accesscheck;
|
|
LARGE_INTEGER close;
|
|
LARGE_INTEGER revert;
|
|
LARGE_INTEGER freq;
|
|
|
|
#if 0
|
|
QueryPerformanceCounter( &start );
|
|
#endif
|
|
status = RpcImpersonateClient( binding );
|
|
#if 0
|
|
QueryPerformanceCounter( &impersonate );
|
|
#endif
|
|
if (status == RPC_S_OK)
|
|
{
|
|
// Get the thread token.
|
|
success = OpenThreadToken( GetCurrentThread(), TOKEN_READ,
|
|
TRUE, &token );
|
|
#if 0
|
|
QueryPerformanceCounter( &open );
|
|
#endif
|
|
if (!success)
|
|
{
|
|
printf( "Could not OpenThreadToken.\n" );
|
|
status = E_FAIL;
|
|
}
|
|
|
|
// Check access.
|
|
else
|
|
{
|
|
gmap.GenericRead = READ_CONTROL;
|
|
gmap.GenericWrite = READ_CONTROL;
|
|
gmap.GenericExecute = READ_CONTROL;
|
|
gmap.GenericAll = READ_CONTROL;
|
|
privilege.PrivilegeCount = 1;
|
|
privilege.Control = 0;
|
|
success = AccessCheck( GlobalSecurityDescriptor, token, READ_CONTROL,
|
|
&gmap, &privilege, &privilege_size,
|
|
&granted_access, &access );
|
|
#if 0
|
|
QueryPerformanceCounter( &accesscheck );
|
|
#endif
|
|
|
|
if (!success)
|
|
{
|
|
printf( "Bad parameters to AccessCheck: 0x%x.\n",
|
|
GetLastError() );
|
|
status = E_FAIL;
|
|
}
|
|
else if (!access)
|
|
{
|
|
printf( "Could not get access.\n" );
|
|
status = ERROR_ACCESS_DENIED;
|
|
}
|
|
CloseHandle( token );
|
|
#if 0
|
|
QueryPerformanceCounter( &close );
|
|
#endif
|
|
}
|
|
status2 = RpcRevertToSelf();
|
|
#if 0
|
|
QueryPerformanceCounter( &revert );
|
|
QueryPerformanceFrequency( &freq );
|
|
start.QuadPart = 1000000 * (impersonate.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
printf( "RpcImpersonateClient took %duS\n", start.u.LowPart );
|
|
impersonate.QuadPart = 1000000 * (open.QuadPart - impersonate.QuadPart) / freq.QuadPart;
|
|
printf( "OpenThreadToken took %duS\n", impersonate.u.LowPart );
|
|
open.QuadPart = 1000000 * (accesscheck.QuadPart - open.QuadPart) / freq.QuadPart;
|
|
printf( "AccessCheckAndAuditAlarm took %duS\n", open.u.LowPart );
|
|
accesscheck.QuadPart = 1000000 * (close.QuadPart - accesscheck.QuadPart) / freq.QuadPart;
|
|
printf( "CloseHandle took %duS\n", accesscheck.u.LowPart );
|
|
close.QuadPart = 1000000 * (revert.QuadPart - close.QuadPart) / freq.QuadPart;
|
|
printf( "RpcRevertToSelf took %duS\n", close.u.LowPart );
|
|
#endif
|
|
if (status2 != RPC_S_OK)
|
|
status = status2;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
unsigned long xaudit_call( handle_t binding )
|
|
{
|
|
RPC_STATUS status;
|
|
RPC_STATUS status2;
|
|
BOOL success;
|
|
DWORD granted_access;
|
|
BOOL access;
|
|
BOOL ignore;
|
|
HANDLE token;
|
|
GENERIC_MAPPING gmap;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER impersonate;
|
|
LARGE_INTEGER accesscheck;
|
|
LARGE_INTEGER revert;
|
|
LARGE_INTEGER freq;
|
|
|
|
#if 0
|
|
QueryPerformanceCounter( &start );
|
|
#endif
|
|
status = RpcImpersonateClient( binding );
|
|
#if 0
|
|
QueryPerformanceCounter( &impersonate );
|
|
#endif
|
|
if (status == RPC_S_OK)
|
|
{
|
|
// Check access and do audits.
|
|
gmap.GenericRead = READ_CONTROL;
|
|
gmap.GenericWrite = READ_CONTROL;
|
|
gmap.GenericExecute = READ_CONTROL;
|
|
gmap.GenericAll = READ_CONTROL;
|
|
success = AccessCheckAndAuditAlarm( L"Test",
|
|
NULL,
|
|
L"Test Type Name",
|
|
L"Test Name",
|
|
GlobalSecurityDescriptor,
|
|
READ_CONTROL,
|
|
&gmap,
|
|
FALSE,
|
|
&granted_access,
|
|
&access,
|
|
&ignore );
|
|
#if 0
|
|
QueryPerformanceCounter( &accesscheck );
|
|
#endif
|
|
if (!success)
|
|
{
|
|
printf( "Bad parameters to AccessCheckAndAuditAlarm: 0x%x.\n",
|
|
GetLastError() );
|
|
status = E_FAIL;
|
|
}
|
|
else if (!access)
|
|
{
|
|
printf( "Could not get access.\n" );
|
|
status = E_FAIL;
|
|
}
|
|
status2 = RpcRevertToSelf();
|
|
#if 0
|
|
QueryPerformanceCounter( &revert );
|
|
QueryPerformanceFrequency( &freq );
|
|
start.QuadPart = 1000000 * (impersonate.QuadPart - start.QuadPart) / freq.QuadPart;
|
|
printf( "RpcImpersonateClient took %duS\n", start.u.LowPart );
|
|
impersonate.QuadPart = 1000000 * (accesscheck.QuadPart - impersonate.QuadPart) / freq.QuadPart;
|
|
printf( "AccessCheckAndAuditAlarm took %duS\n", impersonate.u.LowPart );
|
|
accesscheck.QuadPart = 1000000 * (revert.QuadPart - accesscheck.QuadPart) / freq.QuadPart;
|
|
printf( "RpcRevertToSelf took %duS\n", accesscheck.u.LowPart );
|
|
#endif
|
|
if (status2 != RPC_S_OK)
|
|
status = status2;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
unsigned long xcheck_client( handle_t binding, error_status_t *error_status )
|
|
{
|
|
HANDLE client_token = NULL;
|
|
HANDLE server_token = NULL;
|
|
TOKEN_USER *client_sid;
|
|
TOKEN_USER *server_sid;
|
|
DWORD count;
|
|
char buffer1[100];
|
|
char buffer2[100];
|
|
HRESULT result = S_OK;
|
|
RPC_STATUS status;
|
|
HANDLE process = NULL;
|
|
|
|
// Get this process's security token.
|
|
*error_status = RPC_S_OK;
|
|
if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &server_token ))
|
|
{
|
|
printf( "Could not GetProcessToken: 0x%x\n", GetLastError() );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get the token's user id.
|
|
if (!GetTokenInformation( server_token, TokenUser, &buffer1, sizeof(buffer1),
|
|
&count ))
|
|
{
|
|
printf( "Could not GetTokenInformation: 0x%x\n", GetLastError() );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
server_sid = (TOKEN_USER *) &buffer1;
|
|
|
|
// Impersonate the client.
|
|
status = RpcImpersonateClient( binding );
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not impersonate client: 0x%x\n", status );
|
|
result = MAKE_WIN32( status );
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get the clients security token.
|
|
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &client_token ))
|
|
{
|
|
printf( "Could not GetProcessToken: 0x%x\n", GetLastError() );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Get the token's user id.
|
|
if (!GetTokenInformation( client_token, TokenUser, &buffer2, sizeof(buffer2),
|
|
&count ))
|
|
{
|
|
printf( "Could not GetTokenInformation: 0x%x\n", GetLastError() );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
client_sid = (TOKEN_USER *) &buffer2;
|
|
|
|
// Compare the client and server.
|
|
if (!EqualSid( server_sid->User.Sid, client_sid->User.Sid))
|
|
{
|
|
printf( "Client and server have different SIDs.\n" );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Try to open this process while impersonating the client.
|
|
process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
|
|
if (process == NULL)
|
|
{
|
|
printf( "Could not open process.\n" );
|
|
result = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Undo the impersonation.
|
|
status = RpcRevertToSelf();
|
|
if (status != RPC_S_OK)
|
|
{
|
|
printf( "Could not revert to self: 0x%x\n", status );
|
|
result = MAKE_WIN32( status );
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
if (client_token != NULL)
|
|
CloseHandle( client_token );
|
|
if (server_token != NULL)
|
|
CloseHandle( server_token );
|
|
if (process != NULL)
|
|
CloseHandle( process );
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void xget_interface_buffer( handle_t binding, long *buf_size,
|
|
unsigned char **buffer, SAptId *id,
|
|
error_status_t *status )
|
|
{
|
|
SGetInterface get_interface;
|
|
|
|
*buffer = NULL;
|
|
get_interface.buf_size = buf_size;
|
|
get_interface.buffer = buffer;
|
|
get_interface.thread = GetCurrentThreadId();
|
|
*status = switch_thread( thread_get_interface_buffer, (void *) &get_interface );
|
|
if (*status == RPC_S_OK)
|
|
*status = get_interface.status;
|
|
InterlockedIncrement( &GlobalClients );
|
|
InterlockedIncrement( &GlobalTotal );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
unsigned long ximpersonate_call( handle_t binding )
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
status = RpcImpersonateClient( binding );
|
|
if (status == RPC_S_OK)
|
|
status = RpcRevertToSelf();
|
|
|
|
return status;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void xnullcall( handle_t binding )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void xrelease_interface( handle_t binding, error_status_t *status )
|
|
{
|
|
*status = RPC_S_OK;
|
|
InterlockedDecrement( &GlobalClients );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
void xset_status( handle_t binding, HRESULT result, error_status_t *status )
|
|
{
|
|
RawResult = result;
|
|
*status = RPC_S_OK;
|
|
SetEvent( RawEvent );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
unsigned long xtest( handle_t binding, ITest *obj, SAptId id,
|
|
error_status_t *status )
|
|
{
|
|
*status = RPC_S_OK;
|
|
return obj->check( id );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
unsigned long xtransitive( handle_t handle, wchar_t *binding )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|