summaryrefslogtreecommitdiffstats
path: root/private/oleutest/channel
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/oleutest/channel
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/oleutest/channel')
-rw-r--r--private/oleutest/channel/app/app.cxx9685
-rw-r--r--private/oleutest/channel/app/app_i.c28
-rw-r--r--private/oleutest/channel/app/makefile20
-rw-r--r--private/oleutest/channel/app/prxydll.def7
-rw-r--r--private/oleutest/channel/app/sources70
-rw-r--r--private/oleutest/channel/dirs38
-rw-r--r--private/oleutest/channel/idl/dog.acf9
-rw-r--r--private/oleutest/channel/idl/dog.idl45
-rw-r--r--private/oleutest/channel/idl/itest.acf4
-rw-r--r--private/oleutest/channel/idl/itest.idl192
-rw-r--r--private/oleutest/channel/idl/makefile9
-rw-r--r--private/oleutest/channel/idl/makefile.inc37
-rw-r--r--private/oleutest/channel/idl/pch.cxx18
-rw-r--r--private/oleutest/channel/idl/prxydll.def47
-rw-r--r--private/oleutest/channel/idl/sources66
-rw-r--r--private/oleutest/channel/idl/test.reg24
-rw-r--r--private/oleutest/channel/idl/test2.reg16
-rw-r--r--private/oleutest/channel/rel.cmd3
18 files changed, 10318 insertions, 0 deletions
diff --git a/private/oleutest/channel/app/app.cxx b/private/oleutest/channel/app/app.cxx
new file mode 100644
index 000000000..e7c565a4f
--- /dev/null
+++ b/private/oleutest/channel/app/app.cxx
@@ -0,0 +1,9685 @@
+//--------------------------------------------------------------
+//
+// 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, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ copy = NULL;
+
+ // Time copying the binding handle.
+ time_copy = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ status = RpcBindingCopy( handle, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ 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, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ copy = NULL;
+
+ // Time copying the binding handle.
+ time_copy_secure = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ status = RpcBindingCopy( handle, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ 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( &copy );
+ 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( &nothing );
+ 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( &reg_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 **) &copy );
+ QueryPerformanceCounter( &copy_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 **) &copy1 );
+ 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 **) &copy1 );
+ 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 **) &copy2 );
+ 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 **) &copy3 );
+ 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 **) &copy2 );
+ 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( &nothing );
+ 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, &params, 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;
+}
+
+
+
diff --git a/private/oleutest/channel/app/app_i.c b/private/oleutest/channel/app/app_i.c
new file mode 100644
index 000000000..06ffc5e19
--- /dev/null
+++ b/private/oleutest/channel/app/app_i.c
@@ -0,0 +1,28 @@
+#pragma warning(disable:4101) // Ignore variable not use warning
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: iperf_i.c
+//
+// Contents: IID_IPerf
+//
+// History: Created by Microsoft (R) MIDL Compiler Version 1.10.83
+//
+//--------------------------------------------------------------------------
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+
+const IID CLSID_ITest =
+{0x60000430, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}};
+
+const IID CLSID_ITestMulti =
+{0x25724a70, 0x283f, 0x11ce, {0x95, 0x31, 0x08, 0x00, 0x2b, 0x2a, 0xb6, 0x12}};
diff --git a/private/oleutest/channel/app/makefile b/private/oleutest/channel/app/makefile
new file mode 100644
index 000000000..8991c0d2e
--- /dev/null
+++ b/private/oleutest/channel/app/makefile
@@ -0,0 +1,20 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+!include $(NTMAKEENV)\makefile.def
+
+!else # NTMAKEENV
+
+default: all
+
+!include $(CAIROLE)\com\makefile
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/channel/app/prxydll.def b/private/oleutest/channel/app/prxydll.def
new file mode 100644
index 000000000..f812a2719
--- /dev/null
+++ b/private/oleutest/channel/app/prxydll.def
@@ -0,0 +1,7 @@
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
diff --git a/private/oleutest/channel/app/sources b/private/oleutest/channel/app/sources
new file mode 100644
index 000000000..02bc2d3bb
--- /dev/null
+++ b/private/oleutest/channel/app/sources
@@ -0,0 +1,70 @@
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# This is the name of the target built from the source files specified
+# below. The name should include neither the path nor the file extension.
+#
+
+TARGETNAME= app
+
+#
+# This specifies where the target is to be built. A private target of
+# type LIBRARY or DYNLINK should go to obj, whereas a public target of
+# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib.
+#
+
+TARGETPATH= obj
+
+#
+# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY,
+# etc.
+#
+
+TARGETTYPE= PROGRAM
+
+#DLLDEF= ..\proxy\prxydll.def
+LINKER_FLAGS=-DEF:prxydll.def
+
+INCLUDES= ..\idl;$(BASEDIR)\private\dcomidl\daytona;$(BASEDIR)\private\dcomidl\obj
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ app.cxx \
+ dog_c.c \
+ dog_s.c \
+ itest_p.c \
+ itest_i.c \
+ dlldata.c
+
+
+UMTYPE= console
+UMENTRY=
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\libcmt.lib \
+ $(BASEDIR)\public\sdk\lib\*\security.lib
+
diff --git a/private/oleutest/channel/dirs b/private/oleutest/channel/dirs
new file mode 100644
index 000000000..cda324fa1
--- /dev/null
+++ b/private/oleutest/channel/dirs
@@ -0,0 +1,38 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Dean Edwards (DeanE) 11-Jan-1994
+
+!ENDIF
+
+#
+# This is a list of all subdirectories that build required components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+DIRS= \
+ idl \
+ app
+
+#
+# This is a list of all subdirectories that build optional components.
+# Each subdirectory name should appear on a line by itself. The build
+# follows the order in which the subdirectories are specified.
+#
+
+OPTIONAL_DIRS=
+
diff --git a/private/oleutest/channel/idl/dog.acf b/private/oleutest/channel/idl/dog.acf
new file mode 100644
index 000000000..8c67cfe4c
--- /dev/null
+++ b/private/oleutest/channel/idl/dog.acf
@@ -0,0 +1,9 @@
+interface IDog
+
+{
+ check_client ( [comm_status, fault_status] status );
+ get_interface_buffer ( [comm_status, fault_status] status );
+ release_interface ( [comm_status, fault_status] status );
+ set_status ( [comm_status, fault_status] status );
+ test ( [comm_status, fault_status] status );
+}
diff --git a/private/oleutest/channel/idl/dog.idl b/private/oleutest/channel/idl/dog.idl
new file mode 100644
index 000000000..97d6e3d0c
--- /dev/null
+++ b/private/oleutest/channel/idl/dog.idl
@@ -0,0 +1,45 @@
+//+-------------------------------------------------------------------
+//
+// Interface: IDog
+//
+// Purpose: Interface for manipulating performance
+//
+// History: 8 Nov 94 AlexMit Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+import "itest.idl";
+
+[ uuid(e0b4ab10-fb6d-11cd-b3ae-00aa003c9fdc),
+ version(0.1),
+ pointer_default(unique) ]
+
+interface IDog
+{
+ unsigned long acl_call ( [in] handle_t handle );
+ unsigned long audit_call ( [in] handle_t handle );
+ unsigned long check_client ( [in] handle_t handle,
+ [out] error_status_t *status );
+ void get_interface_buffer ( [in] handle_t handle,
+ [out] long *size,
+ [out, size_is(,*size)] char **buffer,
+ [out] SAptId *id,
+ [out] error_status_t *status );
+ unsigned long impersonate_call ( [in] handle_t handle );
+ void nullcall ( [in] handle_t handle );
+ void release_interface ( [in] handle_t handle,
+ [out] error_status_t *status );
+ void set_status ( [in] handle_t handle,
+ [in] long result,
+ [out] error_status_t *status );
+ unsigned long test ( [in] handle_t handle,
+ [in] ITest *obj,
+ [in] SAptId id,
+ [out] error_status_t *status );
+ unsigned long transitive ( [in] handle_t handle,
+ [in, string] wchar_t *binding );
+}
+
+
diff --git a/private/oleutest/channel/idl/itest.acf b/private/oleutest/channel/idl/itest.acf
new file mode 100644
index 000000000..d11570c04
--- /dev/null
+++ b/private/oleutest/channel/idl/itest.acf
@@ -0,0 +1,4 @@
+interface ITest
+{
+ typedef [allocate(dont_free)] STRING;
+}
diff --git a/private/oleutest/channel/idl/itest.idl b/private/oleutest/channel/idl/itest.idl
new file mode 100644
index 000000000..7f2437650
--- /dev/null
+++ b/private/oleutest/channel/idl/itest.idl
@@ -0,0 +1,192 @@
+//[ ITest_itf
+//+-------------------------------------------------------------------
+//
+// Interface: ITest (ib)
+//
+// Purpose: Interface for manipulating performance
+//
+// History: 5-Oct-93 AlexMit Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[
+ object,
+ uuid(60000200-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+
+interface ITest : IUnknown
+{
+ import "unknwn.idl";
+ import "objidl.idl";
+
+ typedef struct
+ {
+ DWORD process;
+ DWORD thread;
+ DWORD sequence;
+ } SAptId;
+
+ typedef struct
+ {
+ UCHAR Value[6];
+ } HACKHACKHACK_SID_IDENTIFIER_AUTHORITY;
+
+ typedef struct
+ {
+ UCHAR Revision;
+ UCHAR SubAuthorityCount;
+ HACKHACKHACK_SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
+#ifdef MIDL_PASS
+ [size_is(SubAuthorityCount)] ULONG SubAuthority[*];
+#else // MIDL_PASS
+ ULONG SubAuthority[ANYSIZE_ARRAY];
+#endif // MIDL_PASS
+ } HACKSID;
+
+ typedef [string] wchar_t *STRING;
+
+ typedef [transmit_as(DWORD)] DWORD transmit_crash;
+
+ HRESULT align ( [in] unsigned char x[17] );
+ HRESULT call_canceled ( [in] long recurse, [in] long cancel,
+ [in] ITest *callback );
+ HRESULT call_dead ();
+ HRESULT call_me_back ( [in] ITest *callback );
+ HRESULT call_next ();
+ HRESULT callback ();
+ HRESULT cancel ();
+ HRESULT cancel_now ();
+ HRESULT cancel_pending_call ( [out] DWORD *thread );
+ HRESULT cancel_stress ( [in] ITest *obj );
+ HRESULT catch_at_top ( [in] BOOL catch_me_im_falling,
+ [in] ITest *callback,
+ [in] STRING binding );
+ HRESULT check ( [in] SAptId id );
+ HRESULT check_hook ( [in] DWORD cg1, [in] DWORD cn1,
+ [in] DWORD sg1, [in] DWORD sn1,
+ [in] DWORD cg2, [in] DWORD cn2,
+ [in] DWORD sg2, [in] DWORD sn2 );
+ HRESULT count ();
+ HRESULT crash_out ( [out] transmit_crash *data );
+ HRESULT delegate ( [in] ITest *obj, [in] SAptId id,
+ [in] HACKSID *caller );
+ HRESULT exit ();
+ HRESULT forget ();
+ HRESULT get_advise ( [out] IAdviseSink **advise );
+ HRESULT get_data ( [in] DWORD isize,
+ [in, unique, size_is(isize)] char *idata,
+ [in] DWORD osize,
+ [out, size_is(,osize)] char **odata );
+ HRESULT get_id ( [out] SAptId *id );
+ HRESULT get_next ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_next_slowly ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_obj_from_new_apt ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_obj_from_this_apt ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_sid ( [out] HACKSID **sid );
+ HRESULT interface_in ( [in] ITest *obj );
+ HRESULT interrupt ( [in] ITest *obj, [in] SAptId id, BOOL go );
+ HRESULT interrupt_marshal ( [in] ITest *obj1, [in] ITest *obj2 );
+ HRESULT make_acl ( [in] HACKSID *allow );
+ HRESULT null ();
+ HRESULT out ( [out] ITest **obj );
+ HRESULT pointer ( [in] DWORD *ptr );
+ HRESULT recurse ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_disconnect ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_excp ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_fatal ( [in] ITest *callback,
+ [in] ULONG catch_depth,
+ [in] ULONG throw_depth,
+ [in] BOOL cancel );
+ HRESULT register_hook ( [in] GUID ext, [in] DWORD seq );
+ HRESULT recurse_interrupt ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_secure ( [in] ITest *callback, [in] ULONG depth,
+ [in] ULONG imp_depth, [in] HACKSID *Caller );
+ HRESULT register_message_filter( BOOL );
+ HRESULT register_rpc ( [in] STRING protseq, [out] STRING *binding );
+ HRESULT reinitialize ();
+ HRESULT reject_next ();
+ HRESULT remember ( [in] ITest *neighbor, [in] SAptId id );
+ HRESULT rest_and_die ();
+ HRESULT retry_next ();
+ HRESULT ring ( [in] DWORD length );
+ HRESULT secure ( [in] SAptId id,
+ [in] DWORD AuthnLevel, [in] DWORD ImpLevel,
+ [in] DWORD AuthnSvc, [in] DWORD AuthzSvc,
+ [in, unique] STRING PrincName,
+ [in] HACKSID *Caller,
+ [out] DWORD *QueryAuthnLevel );
+ HRESULT security_performance ( [out] DWORD *get_call,
+ [out] DWORD *query_client,
+ [out] DWORD *impersonate,
+ [out] DWORD *revert );
+ HRESULT set_state ( [in] DWORD flags, [in] DWORD priority );
+ HRESULT sick ( [in] ULONG throw_val );
+ HRESULT sleep ( [in] ULONG time );
+ HRESULT test ( [in] ULONG gronk );
+
+}
+
+[
+ object,
+ uuid(60000201-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestNoneImp : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000202-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestConnectImp : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000203-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestEncryptImp : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000204-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestNoneId : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000205-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestConnectId : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000206-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestEncryptId : ITest
+{
+ HRESULT dummy();
+}
+
+//]
diff --git a/private/oleutest/channel/idl/makefile b/private/oleutest/channel/idl/makefile
new file mode 100644
index 000000000..510cce95d
--- /dev/null
+++ b/private/oleutest/channel/idl/makefile
@@ -0,0 +1,9 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/channel/idl/makefile.inc b/private/oleutest/channel/idl/makefile.inc
new file mode 100644
index 000000000..d74e26319
--- /dev/null
+++ b/private/oleutest/channel/idl/makefile.inc
@@ -0,0 +1,37 @@
+itest.h: itest.idl
+ midl itest.idl \
+ -Zp8 \
+ -I$(INCLUDES:;= -I) \
+ -ms_ext \
+ -c_ext \
+ -Os \
+ -out ..\app \
+ -header ..\idl\itest.h \
+ -iid ..\app\itest_i.c \
+ $(C_DEFINES) \
+ -DMIDL_PASS
+
+dog.h: dog.idl
+ midl dog.idl \
+ -Zp8 \
+ -I$(INCLUDES:;= -I) \
+ -ms_ext \
+ -c_ext \
+ -Os \
+ -out ..\app \
+ -header ..\idl\dog.h \
+ -iid ..\app\dog_i.c \
+ -prefix server x \
+ $(C_DEFINES) \
+ -DMIDL_PASS
+
+#
+# This target compiles all .idl files into their corresponding _?.c?? and
+# .h components
+#
+allidl: itest.h dog.h
+
+clean:
+ erase itest.h >NUL 2>NUL
+ erase dog.h >NUL 2>NUL
+
diff --git a/private/oleutest/channel/idl/pch.cxx b/private/oleutest/channel/idl/pch.cxx
new file mode 100644
index 000000000..984d8d2bf
--- /dev/null
+++ b/private/oleutest/channel/idl/pch.cxx
@@ -0,0 +1,18 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: PCH.CXX
+//
+// Contents: Precompiled header
+//
+// History: 12-Jul-93 ShannonC Created
+//
+//--------------------------------------------------------------------------
+
+#include "stdrpc.hxx"
+#pragma hdrstop
+
+
+
diff --git a/private/oleutest/channel/idl/prxydll.def b/private/oleutest/channel/idl/prxydll.def
new file mode 100644
index 000000000..e09e1ce91
--- /dev/null
+++ b/private/oleutest/channel/idl/prxydll.def
@@ -0,0 +1,47 @@
+#if 0
+
+ Microsoft Windows
+ Copyright (C) Microsoft Corporation, 1992 - 1992.
+ All rights reserved.
+
+ This .def file is preprocessed by the compiler to create the version for
+ the current build in the appropriate subdir. Basically, whatever you
+ would have used in your code to control what is compiled when can be
+ used in this file for the same purpose. The following defines are in
+ use at the time this file was written:
+
+ FLAT - Used to indicate a NT/DOS7 build
+ i386 - Intel i386/i486 build
+ MIPS - MIPS R3000/R4000 build
+ ALPHA - DEC Alpha build
+ DBG - Used to control Debug/Retail. Set to 1 if Debug,
+ 0 if Retail.
+ WIN31 - Win16 build
+ __OS2__ - OS/2 build (used by CT mostly)
+
+ If none of these are used, it is assumed the entire file can be used
+ for all builds.
+
+#endif
+
+#ifdef FLAT
+
+LIBRARY ITEST
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+#if defined(i386)
+
+ DllGetClassObject=DllGetClassObject@12 @1
+ DllCanUnloadNow=DllCanUnloadNow@0 @2
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/channel/idl/sources b/private/oleutest/channel/idl/sources
new file mode 100644
index 000000000..0112b8e8d
--- /dev/null
+++ b/private/oleutest/channel/idl/sources
@@ -0,0 +1,66 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Dean Edwards (DeanE) 11-Jan-1993
+
+!ENDIF
+
+MAJORCOMP = comutest
+MINORCOMP = channel
+
+#
+# This is the name of the target built from the source files specified
+# below. The name should include neither the path nor the file extension.
+#
+
+TARGETNAME= idl
+
+#
+# This specifies where the target is to be built. A private target of
+# type LIBRARY or DYNLINK should go to obj, whereas a public target of
+# type LIBRARY or DYNLINK should go to $(BASEDIR)\public\sdk\lib.
+#
+
+TARGETPATH= obj
+
+#
+# This specifies the type of the target, such as PROGRAM, DYNLINK, LIBRARY,
+# etc.
+#
+
+TARGETTYPE= LIBRARY
+
+INCLUDES= $(BASEDIR)\public\sdk\inc
+
+C_DEFINES= $(C_DEFINES)
+
+BLDCRT= 1
+
+SOURCES=
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+USE_LIBCMT=
+
+NTTARGETFILE0= allidl
+
+PRECOMPILED_INCLUDE=
+
diff --git a/private/oleutest/channel/idl/test.reg b/private/oleutest/channel/idl/test.reg
new file mode 100644
index 000000000..40112de96
--- /dev/null
+++ b/private/oleutest/channel/idl/test.reg
@@ -0,0 +1,24 @@
+
+; registry entries for ITest interface. these map the interfaces
+; to the proxy/stub code in itest.dll
+
+
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}
+ = ITest
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}\ProxyStubClsid32
+ = {60000494-AB0F-101A-B4AE-08002B30612C}
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}
+ = CPrxyITest
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}\InprocServer32
+ = itest.dll
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}
+ = CTestCF
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}\LocalServer32
+ = app.exe
+
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/channel/idl/test2.reg b/private/oleutest/channel/idl/test2.reg
new file mode 100644
index 000000000..1f8a8407a
--- /dev/null
+++ b/private/oleutest/channel/idl/test2.reg
@@ -0,0 +1,16 @@
+REGEDIT
+
+
+HKEY_CLASSES_ROOT\Interface\{60000494-AB0F-101A-B4AE-08002B30612C} = ITest
+HKEY_CLASSES_ROOT\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}\ProxyStubClsid32 = {60000494-AB0F-101A-B4AE-08002B30612C}
+
+HKEY_CLASSES_ROOT\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C} = CPrxyITest
+HKEY_CLASSES_ROOT\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}\InprocServer32 = itest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C} = CTestCF
+HKEY_CLASSES_ROOT\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}\LocalServer32 = app.exe
+
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/channel/rel.cmd b/private/oleutest/channel/rel.cmd
new file mode 100644
index 000000000..e8b1be215
--- /dev/null
+++ b/private/oleutest/channel/rel.cmd
@@ -0,0 +1,3 @@
+copy proxy\obj\i386\itest.dll \tmp
+copy app\obj\i386\app.exe \tmp
+copy idl\test.reg \tmp