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
GetTlsIndex()57 DWORD GetTlsIndex() {return dwTlsIndex;}
58
59 // DllMain() is the entry-point function for this DLL.
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)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 proccess.
153 //
154 // A good potential woraround 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
MIDL_user_allocate(size_t len)206 extern "C" void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) {
207 return(malloc(len));
208 }
209
MIDL_user_free(void __RPC_FAR * ptr)210 extern "C" void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) {
211 free(ptr);
212 }
213