1 /* 2 * $Header$ 3 * 4 * Copyright 2008 Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 extern "C" { 28 #include <windows.h> 29 #include <LMCons.h> 30 31 #include "dllmain.h" 32 #include "tls.h" 33 #include "cci_debugging.h" 34 #include "ccapi_context.h" 35 #include "ccapi_ipc.h" 36 #include "client.h" 37 38 void cci_process_init__auxinit(); 39 } 40 41 42 #define CCAPI_V2_MUTEX_NAME TEXT("MIT_CCAPI_V4_MUTEX") 43 44 // Process-specific data: 45 static DWORD dwTlsIndex; 46 static char _user[UNLEN+1]; // Username is used as part of the server and client endpoints. 47 static HANDLE sessionToken; 48 static char* ep_prefices[] = {"CCS", "CCAPI"}; 49 HANDLE hCCAPIv2Mutex = NULL; 50 DWORD firstThreadID = 0; 51 52 // These data structures are used by the old CCAPI implementation 53 // to keep track of the state of the RPC connection. All data is static. 54 static Init init; 55 static Client client; 56 57 DWORD GetTlsIndex() {return dwTlsIndex;} 58 59 // DllMain() is the entry-point function for this DLL. 60 BOOL WINAPI DllMain(HINSTANCE hinstDLL, // DLL module handle 61 DWORD fdwReason, // reason called 62 LPVOID lpvReserved) { // reserved 63 64 struct tspdata* ptspdata; 65 BOOL fIgnore; 66 BOOL bStatus; 67 DWORD status = 0; // 0 is success. 68 DWORD maxUN = sizeof(_user); 69 unsigned int i = 0; 70 unsigned int j = 0; 71 72 switch (fdwReason) { 73 // The DLL is loading due to process initialization or a call to LoadLibrary: 74 case DLL_PROCESS_ATTACH: 75 cci_debug_printf("%s DLL_PROCESS_ATTACH", __FUNCTION__); 76 // Process-wide mutex used to allow only one thread at a time into the RPC code: 77 hCCAPIv2Mutex = CreateMutex(NULL, FALSE, CCAPI_V2_MUTEX_NAME); 78 79 // Figure out our username; it's process-wide: 80 bStatus = GetUserName(_user, &maxUN); 81 if (!bStatus) return bStatus; 82 83 // Remove any characters that aren't valid endpoint characters: 84 while (_user[j] != 0) { 85 if (isalnum(_user[j])) _user[i++] = _user[j]; 86 j++; 87 } 88 _user[i] = '\0'; 89 90 // Our logon session is determined in client.cxx, old CCAPI code carried 91 // over to this implementation. 92 93 // Allocate a TLS index: 94 if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE; 95 96 cci_process_init__auxinit(); 97 // Don't break; fallthrough: Initialize the TLS index for first thread. 98 99 // The attached process creates a new thread: 100 case DLL_THREAD_ATTACH: 101 cci_debug_printf("%s DLL_THREAD_ATTACH", __FUNCTION__); 102 // Don't actually rely on this case for allocation of resources. 103 // Applications (like SecureCRT) may have threads already 104 // created (say 'A' and 'B') before the dll is loaded. If the dll 105 // is loaded in thread 'A' but then used in thread 'B', thread 'B' 106 // will never execute this code. 107 fIgnore = TlsSetValue(dwTlsIndex, NULL); 108 109 // Do not call cci_ipc_thread_init() yet; defer until we actually 110 // need it. On XP, cci_ipc_thread_init() will cause additional 111 // threads to be immediately spawned, which will bring us right 112 // back here again ad infinitum, until windows 113 // resources are exhausted. 114 break; 115 116 // The thread of the attached process terminates: 117 case DLL_THREAD_DETACH: 118 cci_debug_printf("%s DLL_THREAD_DETACH", __FUNCTION__); 119 // Release the allocated memory for this thread 120 ptspdata = (struct tspdata*)TlsGetValue(dwTlsIndex); 121 if (ptspdata != NULL) { 122 free(ptspdata); 123 TlsSetValue(dwTlsIndex, NULL); 124 } 125 break; 126 127 // DLL unload due to process termination or FreeLibrary: 128 case DLL_PROCESS_DETACH: 129 cci_debug_printf("%s DLL_PROCESS_DETACH", __FUNCTION__); 130 //++ Copied from previous implementation: 131 // Process Teardown "Problem" 132 // 133 // There are two problems that occur during process teardown: 134 // 135 // 1) Windows (NT/9x/2000) does not keep track of load/unload 136 // ordering dependencies for use in process teardown. 137 // 138 // 2) The RPC exception handling in the RPC calls do not work 139 // during process shutdown in Win9x. 140 // 141 // When a process is being torn down in Windows, the krbcc DLL 142 // may get a DLL_PROCESS_DETACH before other DLLs are done 143 // with it. Thus, it may disconnect from the RPC server 144 // before the last shutdown RPC call. 145 // 146 // On NT/2000, this is ok because the RPC call will fail and just 147 // return an error. 148 // 149 // On Win9x/Me, the RPC exception will not be caught. 150 // However, Win9x ignores exceptions during process shutdown, 151 // so the exception will never be seen unless a debugger is 152 // attached to the process. 153 // 154 // A good potential workaround would be to have a global 155 // variable that denotes whether the DLL is attached to the 156 // process. If it is not, all entrypoints into the DLL should 157 // return failure. 158 // 159 // A not as good workaround is below but ifdefed out. 160 // 161 // However, we can safely ignore this problem since it can 162 // only affects people running debuggers under 9x/Me who are 163 // using multiple DLLs that use this DLL. 164 // 165 WaitForSingleObject( hCCAPIv2Mutex, INFINITE ); 166 167 // return value is ignored, so we set status for debugging purposes 168 status = Client::Cleanup(); 169 status = Init::Cleanup(); 170 ReleaseMutex( hCCAPIv2Mutex ); 171 CloseHandle( hCCAPIv2Mutex ); 172 //-- Copied from previous implementation. 173 174 // Release the allocated memory for this thread: 175 ptspdata = (struct tspdata*)TlsGetValue(dwTlsIndex); 176 if (ptspdata != NULL) 177 free(ptspdata); 178 TlsFree(dwTlsIndex); // Release the TLS index. 179 // Ideally, we would enumerate all other threads here and 180 // release their thread local storage as well. 181 break; 182 183 default: 184 cci_debug_printf("%s unexpected reason %d", __FUNCTION__, fdwReason); 185 break; 186 } 187 188 UNREFERENCED_PARAMETER(hinstDLL); // no whining! 189 UNREFERENCED_PARAMETER(lpvReserved); 190 return status ? FALSE : TRUE; 191 } 192 193 194 #ifdef __cplusplus // If used by C++ code, 195 extern "C" { // we need to export the C interface 196 #endif 197 198 #ifdef __cplusplus 199 } 200 #endif 201 202 /*********************************************************************/ 203 /* MIDL allocate and free */ 204 /*********************************************************************/ 205 206 extern "C" void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) { 207 return(malloc(len)); 208 } 209 210 extern "C" void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) { 211 free(ptr); 212 } 213