summaryrefslogtreecommitdiffstats
path: root/src/ccapi/lib/win/dllmain.cxx
blob: 82cacad9c87cb2e6a5bfe0f7087443d64d373df0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/*
 * $Header$
 *
 * Copyright 2008 Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 * require a specific license from the United States Government.
 * It is the responsibility of any person or organization contemplating
 * export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 */

extern "C" {
#include <windows.h>
#include <LMCons.h>

#include "dllmain.h"
#include "tls.h"
#include "cci_debugging.h"
#include "ccapi_context.h"
#include "ccapi_ipc.h"
#include "client.h"

void cci_process_init__auxinit();
    }


#define CCAPI_V2_MUTEX_NAME     TEXT("MIT_CCAPI_V4_MUTEX")

// Process-specific data:
static DWORD    dwTlsIndex;
static char     _user[UNLEN+1];     // Username is used as part of the server and client endpoints.
static  HANDLE  sessionToken;
static char*    ep_prefices[]   = {"CCS", "CCAPI"};
HANDLE          hCCAPIv2Mutex   = NULL;
DWORD           firstThreadID   = 0;

// These data structures are used by the old CCAPI implementation 
//  to keep track of the state of the RPC connection.  All data is static.
static Init     init;
static Client   client;

DWORD    GetTlsIndex()  {return dwTlsIndex;}

// DllMain() is the entry-point function for this DLL. 
BOOL WINAPI DllMain(HINSTANCE hinstDLL,     // DLL module handle
                    DWORD fdwReason,        // reason called
                    LPVOID lpvReserved) {   // reserved 

    struct tspdata* ptspdata;
    BOOL            fIgnore;
    BOOL            bStatus;
    DWORD           status      = 0;        // 0 is success.
    DWORD           maxUN       = sizeof(_user);
    unsigned int    i           = 0;
    unsigned int    j           = 0;
 
    switch (fdwReason) { 
        // The DLL is loading due to process initialization or a call to LoadLibrary:
        case DLL_PROCESS_ATTACH: 
            cci_debug_printf("%s DLL_PROCESS_ATTACH", __FUNCTION__);
            // Process-wide mutex used to allow only one thread at a time into the RPC code:
            hCCAPIv2Mutex = CreateMutex(NULL, FALSE, CCAPI_V2_MUTEX_NAME);

            // Figure out our username; it's process-wide:
            bStatus = GetUserName(_user, &maxUN);
            if (!bStatus) return bStatus;

            // Remove any characters that aren't valid endpoint characters:
            while (_user[j] != 0) {
                if (isalnum(_user[j])) _user[i++] = _user[j];
                j++;
                }
            _user[i]    = '\0';

            // Our logon session is determined in client.cxx, old CCAPI code carried
            //  over to this implementation.

            // Allocate a TLS index:
            if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE; 

            cci_process_init__auxinit();
            // Don't break; fallthrough: Initialize the TLS index for first thread.
 
        // The attached process creates a new thread:
        case DLL_THREAD_ATTACH:
            cci_debug_printf("%s DLL_THREAD_ATTACH", __FUNCTION__);
            // Don't actually rely on this case for allocation of resources.
            // Applications (like SecureCRT) may have threads already
            // created (say 'A' and 'B') before the dll is loaded. If the dll
            // is loaded in thread 'A' but then used in thread 'B', thread 'B'
            // will never execute this code.
            fIgnore     = TlsSetValue(dwTlsIndex, NULL);

            // Do not call cci_ipc_thread_init() yet; defer until we actually
            // need it.  On XP, cci_ipc_thread_init() will cause additional
            // threads to be immediately spawned, which will bring us right
            // back here again ad infinitum, until windows
            // resources are exhausted.
            break;
 
        // The thread of the attached process terminates:
        case DLL_THREAD_DETACH: 
            cci_debug_printf("%s DLL_THREAD_DETACH", __FUNCTION__);
            // Release the allocated memory for this thread
            ptspdata = (struct tspdata*)TlsGetValue(dwTlsIndex); 
            if (ptspdata != NULL) {
                free(ptspdata);
                TlsSetValue(dwTlsIndex, NULL); 
                }
            break; 
 
        // DLL unload due to process termination or FreeLibrary:
        case DLL_PROCESS_DETACH: 
            cci_debug_printf("%s DLL_PROCESS_DETACH", __FUNCTION__);
            //++ Copied from previous implementation:
            // Process Teardown "Problem"
            //
            // There are two problems that occur during process teardown:
            //
            // 1) Windows (NT/9x/2000) does not keep track of load/unload
            //    ordering dependencies for use in process teardown.
            //
            // 2) The RPC exception handling in the RPC calls do not work
            //    during process shutdown in Win9x.
            //
            // When a process is being torn down in Windows, the krbcc DLL
            // may get a DLL_PROCESS_DETACH before other DLLs are done
            // with it.  Thus, it may disconnect from the RPC server
            // before the last shutdown RPC call.
            //
            // On NT/2000, this is ok because the RPC call will fail and just
            // return an error.
            //
            // On Win9x/Me, the RPC exception will not be caught.
            // However, Win9x ignores exceptions during process shutdown,
            // so the exception will never be seen unless a debugger is
            // attached to the proccess.
            //
            // A good potential woraround would be to have a global
            // variable that denotes whether the DLL is attached to the
            // process.  If it is not, all entrypoints into the DLL should
            // return failure.
            //
            // A not as good workaround is below but ifdefed out.
            //
            // However, we can safely ignore this problem since it can
            // only affects people running debuggers under 9x/Me who are
            // using multiple DLLs that use this DLL.
            //
            WaitForSingleObject( hCCAPIv2Mutex, INFINITE );
#if 0
            bool process_teardown_workaround = false;
            if (lpvReserved) {
                Init::InitInfo info;
                status = Init::Info(info);
                if (status) break;
                if (!info.isNT) process_teardown_workaround = true;
            }
            if (process_teardown_workaround)
                break;
#endif
            // return value is ignored, so we set status for debugging purposes
            status = Client::Cleanup();
            status = Init::Cleanup();
            ReleaseMutex( hCCAPIv2Mutex );
            CloseHandle( hCCAPIv2Mutex );
            //-- Copied from previous implementation.

            // Release the allocated memory for this thread:
            ptspdata = (struct tspdata*)TlsGetValue(dwTlsIndex); 
            if (ptspdata != NULL)
                free(ptspdata);
            TlsFree(dwTlsIndex);    // Release the TLS index.
            // Ideally, we would enumerate all other threads here and
            // release their thread local storage as well.
            break; 
 
        default:
            cci_debug_printf("%s unexpected reason %d", __FUNCTION__, fdwReason);
            break;
        } 
 
    UNREFERENCED_PARAMETER(hinstDLL);       // no whining!
    UNREFERENCED_PARAMETER(lpvReserved); 
    return status ? FALSE : TRUE;
}


#ifdef __cplusplus    // If used by C++ code, 
extern "C" {          // we need to export the C interface
#endif

#ifdef __cplusplus
}
#endif

/*********************************************************************/
/*                 MIDL allocate and free                            */
/*********************************************************************/

extern "C" void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) {
    return(malloc(len));
    }

extern "C" void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) {
    free(ptr);
    }