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