1*7f2fe78bSCy Schubert /*
2*7f2fe78bSCy Schubert * $Header$
3*7f2fe78bSCy Schubert *
4*7f2fe78bSCy Schubert * Copyright 2008 Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert * All Rights Reserved.
6*7f2fe78bSCy Schubert *
7*7f2fe78bSCy Schubert * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert * require a specific license from the United States Government.
9*7f2fe78bSCy Schubert * It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert * export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert *
12*7f2fe78bSCy Schubert * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert * permission. Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert * this software for any purpose. It is provided "as is" without express
24*7f2fe78bSCy Schubert * or implied warranty.
25*7f2fe78bSCy Schubert */
26*7f2fe78bSCy Schubert
27*7f2fe78bSCy Schubert #include "process.h"
28*7f2fe78bSCy Schubert #include "windows.h"
29*7f2fe78bSCy Schubert
30*7f2fe78bSCy Schubert extern "C" {
31*7f2fe78bSCy Schubert #include "ccs_common.h"
32*7f2fe78bSCy Schubert #include "ccs_os_notify.h"
33*7f2fe78bSCy Schubert #include "ccs_os_server.h"
34*7f2fe78bSCy Schubert #include "ccs_reply.h"
35*7f2fe78bSCy Schubert #include "ccs_request.h"
36*7f2fe78bSCy Schubert #include "win-utils.h"
37*7f2fe78bSCy Schubert #include "ccutils.h"
38*7f2fe78bSCy Schubert }
39*7f2fe78bSCy Schubert
40*7f2fe78bSCy Schubert #include "WorkQueue.h"
41*7f2fe78bSCy Schubert #include "util.h"
42*7f2fe78bSCy Schubert #include "opts.hxx"
43*7f2fe78bSCy Schubert #include "init.hxx"
44*7f2fe78bSCy Schubert
45*7f2fe78bSCy Schubert #pragma warning (disable : 4996)
46*7f2fe78bSCy Schubert
47*7f2fe78bSCy Schubert BOOL bListen = TRUE; /* Why aren't bool and true defined? */
48*7f2fe78bSCy Schubert const char* sessID = NULL; /* The logon session we are running on behalf of. */
49*7f2fe78bSCy Schubert time_t _sst = 0;
50*7f2fe78bSCy Schubert unsigned char* pszNetworkAddress = NULL;
51*7f2fe78bSCy Schubert unsigned char* pszStringBinding = NULL;
52*7f2fe78bSCy Schubert BOOL bRpcHandleInited = FALSE;
53*7f2fe78bSCy Schubert _RPC_ASYNC_STATE* rpcState = NULL;
54*7f2fe78bSCy Schubert
55*7f2fe78bSCy Schubert /* Thread procedures can take only one void* argument. We put all the args we want
56*7f2fe78bSCy Schubert to pass into this struct and then pass a pointer to the struct: */
57*7f2fe78bSCy Schubert struct RpcRcvArgs {
58*7f2fe78bSCy Schubert char* networkAddress;
59*7f2fe78bSCy Schubert unsigned char* protocolSequence;
60*7f2fe78bSCy Schubert unsigned char* sessID; /* Used for this server's endpoint */
61*7f2fe78bSCy Schubert unsigned char* uuid; /* Used for client's UUID */
62*7f2fe78bSCy Schubert ParseOpts::Opts* opts;
63*7f2fe78bSCy Schubert RPC_STATUS status;
64*7f2fe78bSCy Schubert } rpcargs = { NULL, /* pszNetworkAddress */
65*7f2fe78bSCy Schubert (unsigned char*)"ncalrpc", /* pszProtocolSequence */
66*7f2fe78bSCy Schubert NULL, /* sessID placeholder */
67*7f2fe78bSCy Schubert NULL, /* uuid placeholder */
68*7f2fe78bSCy Schubert NULL }; /* Opts placeholder */
69*7f2fe78bSCy Schubert
70*7f2fe78bSCy Schubert /* Command line format:
71*7f2fe78bSCy Schubert argv[0] Program name
72*7f2fe78bSCy Schubert argv[1] session ID to use
73*7f2fe78bSCy Schubert argv[2] "D" Debug: go into infinite loop in ccs_os_server_initialize so process
74*7f2fe78bSCy Schubert can be attached in debugger.
75*7f2fe78bSCy Schubert Any other value: continue
76*7f2fe78bSCy Schubert */
77*7f2fe78bSCy Schubert #define N_FIXED_ARGS 3
78*7f2fe78bSCy Schubert #define SERVER_REPLY_RPC_HANDLE ccs_reply_IfHandle
79*7f2fe78bSCy Schubert
80*7f2fe78bSCy Schubert /* Forward declarations: */
81*7f2fe78bSCy Schubert void receiveLoop(void* rpcargs);
82*7f2fe78bSCy Schubert void connectionListener(void* rpcargs);
83*7f2fe78bSCy Schubert void Usage(const char* argv0);
84*7f2fe78bSCy Schubert void printError(TCHAR* msg);
setMySST()85*7f2fe78bSCy Schubert void setMySST() {_sst = time(&_sst);}
getMySST()86*7f2fe78bSCy Schubert time_t getMySST() {return _sst;}
87*7f2fe78bSCy Schubert RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe);
88*7f2fe78bSCy Schubert void RPC_ENTRY clientListener( _RPC_ASYNC_STATE*,
89*7f2fe78bSCy Schubert void* Context,
90*7f2fe78bSCy Schubert RPC_ASYNC_EVENT Event);
91*7f2fe78bSCy Schubert RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface,
92*7f2fe78bSCy Schubert IN void *Context);
93*7f2fe78bSCy Schubert RPC_STATUS send_init(char* clientUUID);
94*7f2fe78bSCy Schubert //DWORD alloc_name(LPSTR* pname, LPSTR postfix);
95*7f2fe78bSCy Schubert
96*7f2fe78bSCy Schubert
97*7f2fe78bSCy Schubert /* The layout of the rest of this module:
98*7f2fe78bSCy Schubert
99*7f2fe78bSCy Schubert The four entrypoints defined in ccs_os_server.h:
100*7f2fe78bSCy Schubert ccs_os_server_initialize
101*7f2fe78bSCy Schubert cc_int32 ccs_os_server_cleanup
102*7f2fe78bSCy Schubert cc_int32 ccs_os_server_listen_loop
103*7f2fe78bSCy Schubert cc_int32 ccs_os_server_send_reply
104*7f2fe78bSCy Schubert
105*7f2fe78bSCy Schubert Other routines needed by those four.
106*7f2fe78bSCy Schubert */
107*7f2fe78bSCy Schubert
108*7f2fe78bSCy Schubert /* ------------------------------------------------------------------------ */
109*7f2fe78bSCy Schubert
ccs_os_server_initialize(int argc,const char * argv[])110*7f2fe78bSCy Schubert cc_int32 ccs_os_server_initialize (int argc, const char *argv[]) {
111*7f2fe78bSCy Schubert cc_int32 err = 0;
112*7f2fe78bSCy Schubert ParseOpts::Opts opts = { 0 };
113*7f2fe78bSCy Schubert ParseOpts PO;
114*7f2fe78bSCy Schubert BOOL bAdjustedShutdown = FALSE;
115*7f2fe78bSCy Schubert HMODULE hKernel32 = GetModuleHandle("kernel32");
116*7f2fe78bSCy Schubert
117*7f2fe78bSCy Schubert if (!err) {
118*7f2fe78bSCy Schubert sessID = argv[1];
119*7f2fe78bSCy Schubert setMySST();
120*7f2fe78bSCy Schubert
121*7f2fe78bSCy Schubert opts.cMinCalls = 1;
122*7f2fe78bSCy Schubert opts.cMaxCalls = 20;
123*7f2fe78bSCy Schubert opts.fDontWait = TRUE;
124*7f2fe78bSCy Schubert
125*7f2fe78bSCy Schubert #ifdef CCAPI_TEST_OPTIONS
126*7f2fe78bSCy Schubert PO.SetValidOpts("kemnfubc");
127*7f2fe78bSCy Schubert #else
128*7f2fe78bSCy Schubert PO.SetValidOpts("kc");
129*7f2fe78bSCy Schubert #endif
130*7f2fe78bSCy Schubert
131*7f2fe78bSCy Schubert PO.Parse(opts, argc, (char**)argv);
132*7f2fe78bSCy Schubert
133*7f2fe78bSCy Schubert // while(*argv[2] == 'D') {} /* Hang here to attach process with debugger. */
134*7f2fe78bSCy Schubert
135*7f2fe78bSCy Schubert if (hKernel32) {
136*7f2fe78bSCy Schubert typedef BOOL (WINAPI *FP_SetProcessShutdownParameters)(DWORD, DWORD);
137*7f2fe78bSCy Schubert FP_SetProcessShutdownParameters pSetProcessShutdownParameters =
138*7f2fe78bSCy Schubert (FP_SetProcessShutdownParameters)
139*7f2fe78bSCy Schubert GetProcAddress(hKernel32, "SetProcessShutdownParameters");
140*7f2fe78bSCy Schubert if (pSetProcessShutdownParameters) {
141*7f2fe78bSCy Schubert bAdjustedShutdown = pSetProcessShutdownParameters(100, 0);
142*7f2fe78bSCy Schubert }
143*7f2fe78bSCy Schubert }
144*7f2fe78bSCy Schubert cci_debug_printf("%s Shutdown Parameters",
145*7f2fe78bSCy Schubert bAdjustedShutdown ? "Adjusted" : "Did not adjust");
146*7f2fe78bSCy Schubert
147*7f2fe78bSCy Schubert err = Init::Initialize();
148*7f2fe78bSCy Schubert }
149*7f2fe78bSCy Schubert
150*7f2fe78bSCy Schubert // if (!err) {
151*7f2fe78bSCy Schubert // if (opts.bShutdown) {
152*7f2fe78bSCy Schubert // status = shutdown_server(opts.pszEndpoint);
153*7f2fe78bSCy Schubert // }
154*7f2fe78bSCy Schubert // }
155*7f2fe78bSCy Schubert // else {
156*7f2fe78bSCy Schubert // status = startup_server(opts);
157*7f2fe78bSCy Schubert // }
158*7f2fe78bSCy Schubert
159*7f2fe78bSCy Schubert if (!err) {
160*7f2fe78bSCy Schubert err = worklist_initialize();
161*7f2fe78bSCy Schubert }
162*7f2fe78bSCy Schubert
163*7f2fe78bSCy Schubert if (err) {
164*7f2fe78bSCy Schubert Init::Cleanup();
165*7f2fe78bSCy Schubert fprintf( stderr, "An error occurred while %s the server (%u)\n",
166*7f2fe78bSCy Schubert opts.bShutdown ? "shutting down" : "starting/running",
167*7f2fe78bSCy Schubert err);
168*7f2fe78bSCy Schubert exit(cci_check_error (err));
169*7f2fe78bSCy Schubert }
170*7f2fe78bSCy Schubert
171*7f2fe78bSCy Schubert return cci_check_error (err);
172*7f2fe78bSCy Schubert }
173*7f2fe78bSCy Schubert
174*7f2fe78bSCy Schubert /* ------------------------------------------------------------------------ */
175*7f2fe78bSCy Schubert
ccs_os_server_cleanup(int argc,const char * argv[])176*7f2fe78bSCy Schubert cc_int32 ccs_os_server_cleanup (int argc, const char *argv[]) {
177*7f2fe78bSCy Schubert cc_int32 err = 0;
178*7f2fe78bSCy Schubert
179*7f2fe78bSCy Schubert cci_debug_printf("%s for user <%s> shutting down.", argv[0], argv[1]);
180*7f2fe78bSCy Schubert
181*7f2fe78bSCy Schubert worklist_cleanup();
182*7f2fe78bSCy Schubert
183*7f2fe78bSCy Schubert return cci_check_error (err);
184*7f2fe78bSCy Schubert }
185*7f2fe78bSCy Schubert
186*7f2fe78bSCy Schubert /* ------------------------------------------------------------------------ */
187*7f2fe78bSCy Schubert
188*7f2fe78bSCy Schubert /* This function takes work items off the work queue and executes them.
189*7f2fe78bSCy Schubert * This is the one and only place where the multi-threaded Windows code
190*7f2fe78bSCy Schubert * calls into the single-threaded common code.
191*7f2fe78bSCy Schubert *
192*7f2fe78bSCy Schubert * The actual 'listening' for requests from clients happens after receiveloop
193*7f2fe78bSCy Schubert * establishes the RPC endpoint the clients will connect to and the RPC procedures
194*7f2fe78bSCy Schubert * put the work items into the work queue.
195*7f2fe78bSCy Schubert */
ccs_os_server_listen_loop(int argc,const char * argv[])196*7f2fe78bSCy Schubert cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[]) {
197*7f2fe78bSCy Schubert cc_int32 err = 0;
198*7f2fe78bSCy Schubert uintptr_t threadStatus;
199*7f2fe78bSCy Schubert
200*7f2fe78bSCy Schubert ParseOpts::Opts opts = { 0 };
201*7f2fe78bSCy Schubert ParseOpts PO;
202*7f2fe78bSCy Schubert BOOL bQuitIfNoClients = FALSE;
203*7f2fe78bSCy Schubert
204*7f2fe78bSCy Schubert opts.cMinCalls = 1;
205*7f2fe78bSCy Schubert opts.cMaxCalls = 20;
206*7f2fe78bSCy Schubert opts.fDontWait = TRUE;
207*7f2fe78bSCy Schubert
208*7f2fe78bSCy Schubert #ifdef CCAPI_TEST_OPTIONS
209*7f2fe78bSCy Schubert PO.SetValidOpts("kemnfubc");
210*7f2fe78bSCy Schubert #else
211*7f2fe78bSCy Schubert PO.SetValidOpts("kc");
212*7f2fe78bSCy Schubert #endif
213*7f2fe78bSCy Schubert PO.Parse(opts, argc, (char**)argv);
214*7f2fe78bSCy Schubert
215*7f2fe78bSCy Schubert
216*7f2fe78bSCy Schubert //++ debug stuff
217*7f2fe78bSCy Schubert #define INFO_BUFFER_SIZE 32767
218*7f2fe78bSCy Schubert TCHAR infoBuf[INFO_BUFFER_SIZE];
219*7f2fe78bSCy Schubert DWORD bufCharCount = INFO_BUFFER_SIZE;
220*7f2fe78bSCy Schubert // Get and display the user name.
221*7f2fe78bSCy Schubert bufCharCount = INFO_BUFFER_SIZE;
222*7f2fe78bSCy Schubert if( !GetUserName( infoBuf, &bufCharCount ) ) printError( TEXT("GetUserName") );
223*7f2fe78bSCy Schubert //--
224*7f2fe78bSCy Schubert
225*7f2fe78bSCy Schubert /* Sending the reply from within the request RPC handler doesn't seem to work.
226*7f2fe78bSCy Schubert So we listen for requests in a separate thread and put the requests in a
227*7f2fe78bSCy Schubert queue. */
228*7f2fe78bSCy Schubert rpcargs.sessID = (unsigned char*)sessID;
229*7f2fe78bSCy Schubert rpcargs.opts = &opts;
230*7f2fe78bSCy Schubert /// TODO: check for NULL handle, error, etc. probably move to initialize func...
231*7f2fe78bSCy Schubert threadStatus = _beginthread(receiveLoop, 0, (void*)&rpcargs);
232*7f2fe78bSCy Schubert
233*7f2fe78bSCy Schubert /* We handle the queue entries here. Work loop: */
234*7f2fe78bSCy Schubert while (ccs_server_client_count() > 0 || !bQuitIfNoClients) {
235*7f2fe78bSCy Schubert worklist_wait();
236*7f2fe78bSCy Schubert while (!worklist_isEmpty()) {
237*7f2fe78bSCy Schubert k5_ipc_stream buf = NULL;
238*7f2fe78bSCy Schubert long rpcmsg = CCMSG_INVALID;
239*7f2fe78bSCy Schubert time_t serverStartTime = 0xDEADDEAD;
240*7f2fe78bSCy Schubert RPC_STATUS status = 0;
241*7f2fe78bSCy Schubert char* uuid = NULL;
242*7f2fe78bSCy Schubert k5_ipc_stream stream = NULL;
243*7f2fe78bSCy Schubert ccs_pipe_t pipe = NULL;
244*7f2fe78bSCy Schubert ccs_pipe_t pipe2 = NULL;
245*7f2fe78bSCy Schubert
246*7f2fe78bSCy Schubert if (worklist_remove(&rpcmsg, &pipe, &buf, &serverStartTime)) {
247*7f2fe78bSCy Schubert uuid = ccs_win_pipe_getUuid(pipe);
248*7f2fe78bSCy Schubert
249*7f2fe78bSCy Schubert if (serverStartTime <= getMySST()) {
250*7f2fe78bSCy Schubert switch (rpcmsg) {
251*7f2fe78bSCy Schubert case CCMSG_CONNECT: {
252*7f2fe78bSCy Schubert cci_debug_printf(" Processing CONNECT");
253*7f2fe78bSCy Schubert rpcargs.uuid = (unsigned char*)uuid;
254*7f2fe78bSCy Schubert
255*7f2fe78bSCy Schubert // Even if a disconnect message is received before this code finishes,
256*7f2fe78bSCy Schubert // it won't be dequeued and processed until after this code finishes.
257*7f2fe78bSCy Schubert // So we can add the client after starting the connection listener.
258*7f2fe78bSCy Schubert connectionListener((void*)&rpcargs);
259*7f2fe78bSCy Schubert status = rpcargs.status;
260*7f2fe78bSCy Schubert
261*7f2fe78bSCy Schubert if (!status) {
262*7f2fe78bSCy Schubert status = ccs_server_add_client(pipe);
263*7f2fe78bSCy Schubert }
264*7f2fe78bSCy Schubert if (!status) {status = send_connection_reply(pipe);}
265*7f2fe78bSCy Schubert break;
266*7f2fe78bSCy Schubert }
267*7f2fe78bSCy Schubert case CCMSG_DISCONNECT: {
268*7f2fe78bSCy Schubert cci_debug_printf(" Processing DISCONNECT");
269*7f2fe78bSCy Schubert if (!status) {
270*7f2fe78bSCy Schubert status = ccs_server_remove_client(pipe);
271*7f2fe78bSCy Schubert }
272*7f2fe78bSCy Schubert break;
273*7f2fe78bSCy Schubert }
274*7f2fe78bSCy Schubert case CCMSG_REQUEST:
275*7f2fe78bSCy Schubert cci_debug_printf(" Processing REQUEST");
276*7f2fe78bSCy Schubert ccs_pipe_copy(&pipe2, pipe);
277*7f2fe78bSCy Schubert // Dispatch message here, setting both pipes to the client UUID:
278*7f2fe78bSCy Schubert err = ccs_server_handle_request (pipe, pipe2, buf);
279*7f2fe78bSCy Schubert break;
280*7f2fe78bSCy Schubert case CCMSG_PING:
281*7f2fe78bSCy Schubert cci_debug_printf(" Processing PING");
282*7f2fe78bSCy Schubert err = krb5int_ipc_stream_new (&stream);
283*7f2fe78bSCy Schubert err = krb5int_ipc_stream_write(stream, "This is a test of the emergency broadcasting system", 52);
284*7f2fe78bSCy Schubert err = ccs_os_server_send_reply(pipe, stream);
285*7f2fe78bSCy Schubert break;
286*7f2fe78bSCy Schubert case CCMSG_QUIT:
287*7f2fe78bSCy Schubert bQuitIfNoClients = TRUE;
288*7f2fe78bSCy Schubert break;
289*7f2fe78bSCy Schubert default:
290*7f2fe78bSCy Schubert cci_debug_printf("Huh? Received invalid message type %ld from UUID:<%s>",
291*7f2fe78bSCy Schubert rpcmsg, uuid);
292*7f2fe78bSCy Schubert break;
293*7f2fe78bSCy Schubert }
294*7f2fe78bSCy Schubert if (buf) krb5int_ipc_stream_release(buf);
295*7f2fe78bSCy Schubert /* Don't free uuid, which was allocated here. A pointer to it is in the
296*7f2fe78bSCy Schubert rpcargs struct which was passed to connectionListener which will be
297*7f2fe78bSCy Schubert received by ccapi_listen when the client exits. ccapi_listen needs
298*7f2fe78bSCy Schubert the uuid to know which client to disconnect.
299*7f2fe78bSCy Schubert */
300*7f2fe78bSCy Schubert }
301*7f2fe78bSCy Schubert // Server's start time is different from what the client thinks.
302*7f2fe78bSCy Schubert // That means the server has rebooted since the client connected.
303*7f2fe78bSCy Schubert else {
304*7f2fe78bSCy Schubert cci_debug_printf("Whoops! Server has rebooted since client established connection.");
305*7f2fe78bSCy Schubert }
306*7f2fe78bSCy Schubert }
307*7f2fe78bSCy Schubert else {cci_debug_printf("Huh? Queue not empty but no item to remove.");}
308*7f2fe78bSCy Schubert }
309*7f2fe78bSCy Schubert }
310*7f2fe78bSCy Schubert return cci_check_error (err);
311*7f2fe78bSCy Schubert }
312*7f2fe78bSCy Schubert
313*7f2fe78bSCy Schubert /* ------------------------------------------------------------------------ */
314*7f2fe78bSCy Schubert
ccs_os_server_send_reply(ccs_pipe_t in_pipe,k5_ipc_stream in_reply_stream)315*7f2fe78bSCy Schubert cc_int32 ccs_os_server_send_reply (ccs_pipe_t in_pipe,
316*7f2fe78bSCy Schubert k5_ipc_stream in_reply_stream) {
317*7f2fe78bSCy Schubert
318*7f2fe78bSCy Schubert /* ccs_pipe_t in_reply_pipe is a char* reply endpoint.
319*7f2fe78bSCy Schubert k5_ipc_stream in_reply_stream is the data to be sent.
320*7f2fe78bSCy Schubert */
321*7f2fe78bSCy Schubert
322*7f2fe78bSCy Schubert cc_int32 err = 0;
323*7f2fe78bSCy Schubert char* uuid = ccs_win_pipe_getUuid(in_pipe);
324*7f2fe78bSCy Schubert UINT64 h = ccs_win_pipe_getHandle(in_pipe);
325*7f2fe78bSCy Schubert
326*7f2fe78bSCy Schubert if (!err) {
327*7f2fe78bSCy Schubert err = send_init(uuid); // Sets RPC handle to be used.
328*7f2fe78bSCy Schubert }
329*7f2fe78bSCy Schubert
330*7f2fe78bSCy Schubert if (!err) {
331*7f2fe78bSCy Schubert RpcTryExcept {
332*7f2fe78bSCy Schubert long status;
333*7f2fe78bSCy Schubert ccs_rpc_request_reply( // make call with user message
334*7f2fe78bSCy Schubert CCMSG_REQUEST_REPLY, /* Message type */
335*7f2fe78bSCy Schubert (unsigned char*)&h, /* client's tspdata* */
336*7f2fe78bSCy Schubert (unsigned char*)uuid,
337*7f2fe78bSCy Schubert getMySST(),
338*7f2fe78bSCy Schubert krb5int_ipc_stream_size(in_reply_stream), /* Length of buffer */
339*7f2fe78bSCy Schubert (const unsigned char*)krb5int_ipc_stream_data(in_reply_stream), /* Data buffer */
340*7f2fe78bSCy Schubert &status ); /* Return code */
341*7f2fe78bSCy Schubert }
342*7f2fe78bSCy Schubert RpcExcept(1) {
343*7f2fe78bSCy Schubert cci_check_error(RpcExceptionCode());
344*7f2fe78bSCy Schubert }
345*7f2fe78bSCy Schubert RpcEndExcept
346*7f2fe78bSCy Schubert }
347*7f2fe78bSCy Schubert
348*7f2fe78bSCy Schubert /* The calls to the remote procedures are complete. */
349*7f2fe78bSCy Schubert /* Free whatever we allocated: */
350*7f2fe78bSCy Schubert err = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE);
351*7f2fe78bSCy Schubert
352*7f2fe78bSCy Schubert return cci_check_error (err);
353*7f2fe78bSCy Schubert }
354*7f2fe78bSCy Schubert
355*7f2fe78bSCy Schubert
356*7f2fe78bSCy Schubert /* Windows-specific routines: */
357*7f2fe78bSCy Schubert
Usage(const char * argv0)358*7f2fe78bSCy Schubert void Usage(const char* argv0) {
359*7f2fe78bSCy Schubert printf("Usage:\n");
360*7f2fe78bSCy Schubert printf("%s [m maxcalls] [n mincalls] [f dontwait] [h|?]]\n", argv0);
361*7f2fe78bSCy Schubert printf(" CCAPI server process.\n");
362*7f2fe78bSCy Schubert printf(" h|? whow usage message. <\n");
363*7f2fe78bSCy Schubert }
364*7f2fe78bSCy Schubert
365*7f2fe78bSCy Schubert /* ------------------------------------------------------------------------ */
366*7f2fe78bSCy Schubert /* The receive thread repeatedly issues RpcServerListen.
367*7f2fe78bSCy Schubert When a message arrives, it is handled in the RPC procedure.
368*7f2fe78bSCy Schubert */
receiveLoop(void * rpcargs)369*7f2fe78bSCy Schubert void receiveLoop(void* rpcargs) {
370*7f2fe78bSCy Schubert
371*7f2fe78bSCy Schubert struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs;
372*7f2fe78bSCy Schubert RPC_STATUS status = FALSE;
373*7f2fe78bSCy Schubert unsigned char* pszSecurity = NULL;
374*7f2fe78bSCy Schubert LPSTR endpoint = NULL;
375*7f2fe78bSCy Schubert LPSTR event_name = NULL;
376*7f2fe78bSCy Schubert PSECURITY_DESCRIPTOR psd = NULL;
377*7f2fe78bSCy Schubert HANDLE hEvent = 0;
378*7f2fe78bSCy Schubert Init::InitInfo info;
379*7f2fe78bSCy Schubert
380*7f2fe78bSCy Schubert cci_debug_printf("THREAD BEGIN: %s", __FUNCTION__);
381*7f2fe78bSCy Schubert
382*7f2fe78bSCy Schubert status = Init::Info(info);
383*7f2fe78bSCy Schubert
384*7f2fe78bSCy Schubert /* Build complete RPC endpoint using previous CCAPI implementation: */
385*7f2fe78bSCy Schubert if (!status) {
386*7f2fe78bSCy Schubert if (!rcvargs->opts->pszEndpoint) {
387*7f2fe78bSCy Schubert if (!status) {
388*7f2fe78bSCy Schubert status = alloc_name(&endpoint, "ep", isNT());
389*7f2fe78bSCy Schubert }
390*7f2fe78bSCy Schubert
391*7f2fe78bSCy Schubert if (!status) {
392*7f2fe78bSCy Schubert status = alloc_name(&event_name, "startup", isNT());
393*7f2fe78bSCy Schubert }
394*7f2fe78bSCy Schubert
395*7f2fe78bSCy Schubert if (!status) {
396*7f2fe78bSCy Schubert hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name);
397*7f2fe78bSCy Schubert // We ignore any error opening the event because we do not know who started us.
398*7f2fe78bSCy Schubert // [Comment paraphrased from previous implementation, whence it was copied.]
399*7f2fe78bSCy Schubert }
400*7f2fe78bSCy Schubert }
401*7f2fe78bSCy Schubert else {
402*7f2fe78bSCy Schubert endpoint = rcvargs->opts->pszEndpoint;
403*7f2fe78bSCy Schubert }
404*7f2fe78bSCy Schubert }
405*7f2fe78bSCy Schubert
406*7f2fe78bSCy Schubert cci_debug_printf("%s Registering endpoint %s", __FUNCTION__, endpoint);
407*7f2fe78bSCy Schubert
408*7f2fe78bSCy Schubert if (!status && isNT()) {
409*7f2fe78bSCy Schubert status = alloc_own_security_descriptor_NT(&psd);
410*7f2fe78bSCy Schubert }
411*7f2fe78bSCy Schubert
412*7f2fe78bSCy Schubert if (!status) {
413*7f2fe78bSCy Schubert status = RpcServerUseProtseqEp(rcvargs->protocolSequence,
414*7f2fe78bSCy Schubert rcvargs->opts->cMaxCalls,
415*7f2fe78bSCy Schubert (RPC_CSTR)endpoint,
416*7f2fe78bSCy Schubert rcvargs->opts->bDontProtect ? 0 : psd); // SD
417*7f2fe78bSCy Schubert }
418*7f2fe78bSCy Schubert
419*7f2fe78bSCy Schubert if (!status) {
420*7f2fe78bSCy Schubert status = RpcServerRegisterAuthInfo(0, // server principal
421*7f2fe78bSCy Schubert RPC_C_AUTHN_WINNT,
422*7f2fe78bSCy Schubert 0,
423*7f2fe78bSCy Schubert 0);
424*7f2fe78bSCy Schubert }
425*7f2fe78bSCy Schubert
426*7f2fe78bSCy Schubert while (bListen && !status) {
427*7f2fe78bSCy Schubert cci_debug_printf("%s is listening ...", __FUNCTION__);
428*7f2fe78bSCy Schubert
429*7f2fe78bSCy Schubert if (!info.isNT) {
430*7f2fe78bSCy Schubert status = RpcServerRegisterIf(ccs_request_ServerIfHandle, // interface
431*7f2fe78bSCy Schubert NULL, // MgrTypeUuid
432*7f2fe78bSCy Schubert NULL); // MgrEpv; null means use default
433*7f2fe78bSCy Schubert }
434*7f2fe78bSCy Schubert else {
435*7f2fe78bSCy Schubert status = info.fRpcServerRegisterIfEx(ccs_request_ServerIfHandle, // interface
436*7f2fe78bSCy Schubert NULL, // MgrTypeUuid
437*7f2fe78bSCy Schubert NULL, // MgrEpv; 0 means default
438*7f2fe78bSCy Schubert RPC_IF_ALLOW_SECURE_ONLY,
439*7f2fe78bSCy Schubert rcvargs->opts->cMaxCalls,
440*7f2fe78bSCy Schubert rcvargs->opts->bSecCallback ?
441*7f2fe78bSCy Schubert (RPC_IF_CALLBACK_FN*)sec_callback : 0 );
442*7f2fe78bSCy Schubert }
443*7f2fe78bSCy Schubert
444*7f2fe78bSCy Schubert if (!status) {
445*7f2fe78bSCy Schubert status = RpcServerListen(rcvargs->opts->cMinCalls,
446*7f2fe78bSCy Schubert rcvargs->opts->cMaxCalls,
447*7f2fe78bSCy Schubert rcvargs->opts->fDontWait);
448*7f2fe78bSCy Schubert }
449*7f2fe78bSCy Schubert
450*7f2fe78bSCy Schubert if (!status) {
451*7f2fe78bSCy Schubert if (rcvargs->opts->fDontWait) {
452*7f2fe78bSCy Schubert if (hEvent) SetEvent(hEvent); // Ignore any error -- SetEvent is an optimization.
453*7f2fe78bSCy Schubert status = RpcMgmtWaitServerListen();
454*7f2fe78bSCy Schubert }
455*7f2fe78bSCy Schubert }
456*7f2fe78bSCy Schubert }
457*7f2fe78bSCy Schubert
458*7f2fe78bSCy Schubert if (status) { // Cleanup in case of errors:
459*7f2fe78bSCy Schubert if (hEvent) CloseHandle(hEvent);
460*7f2fe78bSCy Schubert free_alloc_p(&event_name);
461*7f2fe78bSCy Schubert free_alloc_p(&psd);
462*7f2fe78bSCy Schubert if (endpoint && (endpoint != rcvargs->opts->pszEndpoint))
463*7f2fe78bSCy Schubert free_alloc_p(&endpoint);
464*7f2fe78bSCy Schubert }
465*7f2fe78bSCy Schubert
466*7f2fe78bSCy Schubert // tell main thread to shutdown since it won't receive any more messages
467*7f2fe78bSCy Schubert worklist_add(CCMSG_QUIT, NULL, NULL, 0);
468*7f2fe78bSCy Schubert _endthread();
469*7f2fe78bSCy Schubert } // End receiveLoop
470*7f2fe78bSCy Schubert
471*7f2fe78bSCy Schubert
472*7f2fe78bSCy Schubert
473*7f2fe78bSCy Schubert /* ------------------------------------------------------------------------ */
474*7f2fe78bSCy Schubert /* The connection listener thread waits forever for a call to the CCAPI_CLIENT_<UUID>
475*7f2fe78bSCy Schubert endpoint, ccapi_listen function to complete. If the call completes or gets an
476*7f2fe78bSCy Schubert RPC exception, it means the client has disappeared.
477*7f2fe78bSCy Schubert
478*7f2fe78bSCy Schubert A separate connectionListener is started for each client that has connected to the server.
479*7f2fe78bSCy Schubert */
480*7f2fe78bSCy Schubert
connectionListener(void * rpcargs)481*7f2fe78bSCy Schubert void connectionListener(void* rpcargs) {
482*7f2fe78bSCy Schubert
483*7f2fe78bSCy Schubert struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs;
484*7f2fe78bSCy Schubert RPC_STATUS status = FALSE;
485*7f2fe78bSCy Schubert char* endpoint;
486*7f2fe78bSCy Schubert unsigned char* pszOptions = NULL;
487*7f2fe78bSCy Schubert unsigned char * pszUuid = NULL;
488*7f2fe78bSCy Schubert
489*7f2fe78bSCy Schubert endpoint = clientEndpoint((char*)rcvargs->uuid);
490*7f2fe78bSCy Schubert rpcState = (RPC_ASYNC_STATE*)malloc(sizeof(RPC_ASYNC_STATE));
491*7f2fe78bSCy Schubert status = RpcAsyncInitializeHandle(rpcState, sizeof(RPC_ASYNC_STATE));
492*7f2fe78bSCy Schubert cci_debug_printf("");
493*7f2fe78bSCy Schubert cci_debug_printf("%s About to LISTEN to <%s>", __FUNCTION__, endpoint);
494*7f2fe78bSCy Schubert
495*7f2fe78bSCy Schubert rpcState->UserInfo = rcvargs->uuid;
496*7f2fe78bSCy Schubert rpcState->NotificationType = RpcNotificationTypeApc;
497*7f2fe78bSCy Schubert rpcState->u.APC.NotificationRoutine = clientListener;
498*7f2fe78bSCy Schubert rpcState->u.APC.hThread = 0;
499*7f2fe78bSCy Schubert
500*7f2fe78bSCy Schubert /* [If in use] Free previous binding: */
501*7f2fe78bSCy Schubert if (bRpcHandleInited) {
502*7f2fe78bSCy Schubert // Free previous binding (could have been used to call ccapi_listen
503*7f2fe78bSCy Schubert // in a different client thread).
504*7f2fe78bSCy Schubert // Don't check result or update status.
505*7f2fe78bSCy Schubert RpcStringFree(&pszStringBinding);
506*7f2fe78bSCy Schubert RpcBindingFree(&SERVER_REPLY_RPC_HANDLE);
507*7f2fe78bSCy Schubert bRpcHandleInited = FALSE;
508*7f2fe78bSCy Schubert }
509*7f2fe78bSCy Schubert
510*7f2fe78bSCy Schubert /* Set up binding to the client's endpoint: */
511*7f2fe78bSCy Schubert if (!status) {
512*7f2fe78bSCy Schubert status = RpcStringBindingCompose(
513*7f2fe78bSCy Schubert pszUuid,
514*7f2fe78bSCy Schubert pszProtocolSequence,
515*7f2fe78bSCy Schubert pszNetworkAddress,
516*7f2fe78bSCy Schubert (RPC_CSTR)endpoint,
517*7f2fe78bSCy Schubert pszOptions,
518*7f2fe78bSCy Schubert &pszStringBinding);
519*7f2fe78bSCy Schubert }
520*7f2fe78bSCy Schubert
521*7f2fe78bSCy Schubert /* Set the binding handle that will be used to bind to the server. */
522*7f2fe78bSCy Schubert if (!status) {
523*7f2fe78bSCy Schubert status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE);
524*7f2fe78bSCy Schubert }
525*7f2fe78bSCy Schubert if (!status) {bRpcHandleInited = TRUE;}
526*7f2fe78bSCy Schubert
527*7f2fe78bSCy Schubert RpcTryExcept {
528*7f2fe78bSCy Schubert cci_debug_printf(" Calling remote procedure ccapi_listen");
529*7f2fe78bSCy Schubert ccapi_listen(rpcState, SERVER_REPLY_RPC_HANDLE, CCMSG_LISTEN, &status);
530*7f2fe78bSCy Schubert /* Asynchronous call will return immediately. */
531*7f2fe78bSCy Schubert }
532*7f2fe78bSCy Schubert RpcExcept(1) {
533*7f2fe78bSCy Schubert status = cci_check_error(RpcExceptionCode());
534*7f2fe78bSCy Schubert }
535*7f2fe78bSCy Schubert RpcEndExcept
536*7f2fe78bSCy Schubert
537*7f2fe78bSCy Schubert rcvargs->status = status;
538*7f2fe78bSCy Schubert } // End connectionListener
539*7f2fe78bSCy Schubert
540*7f2fe78bSCy Schubert
clientListener(_RPC_ASYNC_STATE * pAsync,void * Context,RPC_ASYNC_EVENT Event)541*7f2fe78bSCy Schubert void RPC_ENTRY clientListener(
542*7f2fe78bSCy Schubert _RPC_ASYNC_STATE* pAsync,
543*7f2fe78bSCy Schubert void* Context,
544*7f2fe78bSCy Schubert RPC_ASYNC_EVENT Event
545*7f2fe78bSCy Schubert ) {
546*7f2fe78bSCy Schubert
547*7f2fe78bSCy Schubert ccs_pipe_t pipe = ccs_win_pipe_new((char*)pAsync->UserInfo, NULL);
548*7f2fe78bSCy Schubert
549*7f2fe78bSCy Schubert cci_debug_printf("%s(0x%X, ...) async routine for <0x%X:%s>!",
550*7f2fe78bSCy Schubert __FUNCTION__, pAsync, pAsync->UserInfo, pAsync->UserInfo);
551*7f2fe78bSCy Schubert
552*7f2fe78bSCy Schubert worklist_add( CCMSG_DISCONNECT,
553*7f2fe78bSCy Schubert pipe,
554*7f2fe78bSCy Schubert NULL, /* No payload with connect request */
555*7f2fe78bSCy Schubert (const time_t)0 ); /* No server session number with connect request */
556*7f2fe78bSCy Schubert }
557*7f2fe78bSCy Schubert
558*7f2fe78bSCy Schubert
printError(TCHAR * msg)559*7f2fe78bSCy Schubert void printError( TCHAR* msg ) {
560*7f2fe78bSCy Schubert DWORD eNum;
561*7f2fe78bSCy Schubert TCHAR sysMsg[256];
562*7f2fe78bSCy Schubert TCHAR* p;
563*7f2fe78bSCy Schubert
564*7f2fe78bSCy Schubert eNum = GetLastError( );
565*7f2fe78bSCy Schubert FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
566*7f2fe78bSCy Schubert FORMAT_MESSAGE_IGNORE_INSERTS,
567*7f2fe78bSCy Schubert NULL, eNum,
568*7f2fe78bSCy Schubert MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
569*7f2fe78bSCy Schubert sysMsg, 256, NULL );
570*7f2fe78bSCy Schubert
571*7f2fe78bSCy Schubert // Trim the end of the line and terminate it with a null
572*7f2fe78bSCy Schubert p = sysMsg;
573*7f2fe78bSCy Schubert while( ( *p > 31 ) || ( *p == 9 ) )
574*7f2fe78bSCy Schubert ++p;
575*7f2fe78bSCy Schubert do { *p-- = 0; } while( ( p >= sysMsg ) &&
576*7f2fe78bSCy Schubert ( ( *p == '.' ) || ( *p < 33 ) ) );
577*7f2fe78bSCy Schubert
578*7f2fe78bSCy Schubert // Display the message
579*7f2fe78bSCy Schubert cci_debug_printf("%s failed with error %d (%s)", msg, eNum, sysMsg);
580*7f2fe78bSCy Schubert }
581*7f2fe78bSCy Schubert
582*7f2fe78bSCy Schubert
send_init(char * clientUUID)583*7f2fe78bSCy Schubert RPC_STATUS send_init(char* clientUUID) {
584*7f2fe78bSCy Schubert RPC_STATUS status;
585*7f2fe78bSCy Schubert unsigned char * pszUuid = NULL;
586*7f2fe78bSCy Schubert unsigned char * pszOptions = NULL;
587*7f2fe78bSCy Schubert
588*7f2fe78bSCy Schubert /* Use a convenience function to concatenate the elements of */
589*7f2fe78bSCy Schubert /* the string binding into the proper sequence. */
590*7f2fe78bSCy Schubert status = RpcStringBindingCompose(pszUuid,
591*7f2fe78bSCy Schubert pszProtocolSequence,
592*7f2fe78bSCy Schubert pszNetworkAddress,
593*7f2fe78bSCy Schubert (unsigned char*)clientEndpoint(clientUUID),
594*7f2fe78bSCy Schubert pszOptions,
595*7f2fe78bSCy Schubert &pszStringBinding);
596*7f2fe78bSCy Schubert if (status) {return (status);}
597*7f2fe78bSCy Schubert
598*7f2fe78bSCy Schubert /* Set the binding handle that will be used to bind to the RPC server [the 'client']. */
599*7f2fe78bSCy Schubert status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE);
600*7f2fe78bSCy Schubert return (status);
601*7f2fe78bSCy Schubert }
602*7f2fe78bSCy Schubert
send_finish()603*7f2fe78bSCy Schubert RPC_STATUS send_finish() {
604*7f2fe78bSCy Schubert RPC_STATUS status;
605*7f2fe78bSCy Schubert /* Can't shut down client -- it runs listen function which */
606*7f2fe78bSCy Schubert /* server uses to detect the client going away. */
607*7f2fe78bSCy Schubert
608*7f2fe78bSCy Schubert /* The calls to the remote procedures are complete. */
609*7f2fe78bSCy Schubert /* Free the string and the binding handle */
610*7f2fe78bSCy Schubert status = RpcStringFree(&pszStringBinding); // remote calls done; unbind
611*7f2fe78bSCy Schubert if (status) {return (status);}
612*7f2fe78bSCy Schubert
613*7f2fe78bSCy Schubert status = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); // remote calls done; unbind
614*7f2fe78bSCy Schubert
615*7f2fe78bSCy Schubert return (status);
616*7f2fe78bSCy Schubert }
617*7f2fe78bSCy Schubert
send_connection_reply(ccs_pipe_t in_pipe)618*7f2fe78bSCy Schubert RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe) {
619*7f2fe78bSCy Schubert char* uuid = ccs_win_pipe_getUuid (in_pipe);
620*7f2fe78bSCy Schubert UINT64 h = ccs_win_pipe_getHandle(in_pipe);
621*7f2fe78bSCy Schubert RPC_STATUS status = send_init(uuid);
622*7f2fe78bSCy Schubert
623*7f2fe78bSCy Schubert RpcTryExcept {
624*7f2fe78bSCy Schubert ccs_rpc_connect_reply( // make call with user message
625*7f2fe78bSCy Schubert CCMSG_CONNECT_REPLY, /* Message type */
626*7f2fe78bSCy Schubert (unsigned char*)&h, /* client's tspdata* */
627*7f2fe78bSCy Schubert (unsigned char*)uuid,
628*7f2fe78bSCy Schubert getMySST(), /* Server's session number = its start time */
629*7f2fe78bSCy Schubert &status ); /* Return code */
630*7f2fe78bSCy Schubert }
631*7f2fe78bSCy Schubert RpcExcept(1) {
632*7f2fe78bSCy Schubert cci_check_error(RpcExceptionCode());
633*7f2fe78bSCy Schubert }
634*7f2fe78bSCy Schubert RpcEndExcept
635*7f2fe78bSCy Schubert
636*7f2fe78bSCy Schubert status = send_finish();
637*7f2fe78bSCy Schubert return (status);
638*7f2fe78bSCy Schubert }
639*7f2fe78bSCy Schubert
GetPeerName(RPC_BINDING_HANDLE hClient,LPTSTR pszClientName,int iMaxLen)640*7f2fe78bSCy Schubert RPC_STATUS GetPeerName( RPC_BINDING_HANDLE hClient,
641*7f2fe78bSCy Schubert LPTSTR pszClientName,
642*7f2fe78bSCy Schubert int iMaxLen) {
643*7f2fe78bSCy Schubert RPC_STATUS Status = RPC_S_OK;
644*7f2fe78bSCy Schubert RPC_BINDING_HANDLE hServer = NULL;
645*7f2fe78bSCy Schubert PTBYTE pszStringBinding = NULL;
646*7f2fe78bSCy Schubert PTBYTE pszClientNetAddr = NULL;
647*7f2fe78bSCy Schubert PTBYTE pszProtSequence = NULL;
648*7f2fe78bSCy Schubert
649*7f2fe78bSCy Schubert memset(pszClientName, 0, iMaxLen * sizeof(TCHAR));
650*7f2fe78bSCy Schubert
651*7f2fe78bSCy Schubert __try {
652*7f2fe78bSCy Schubert // Create a partially bound server handle from the client handle.
653*7f2fe78bSCy Schubert Status = RpcBindingServerFromClient (hClient, &hServer);
654*7f2fe78bSCy Schubert if (Status != RPC_S_OK) __leave;
655*7f2fe78bSCy Schubert
656*7f2fe78bSCy Schubert // Get the partially bound server string binding and parse it.
657*7f2fe78bSCy Schubert Status = RpcBindingToStringBinding (hServer,
658*7f2fe78bSCy Schubert &pszStringBinding);
659*7f2fe78bSCy Schubert if (Status != RPC_S_OK) __leave;
660*7f2fe78bSCy Schubert
661*7f2fe78bSCy Schubert // String binding only contains protocol sequence and client
662*7f2fe78bSCy Schubert // address, and is not currently implemented for named pipes.
663*7f2fe78bSCy Schubert Status = RpcStringBindingParse (pszStringBinding, NULL,
664*7f2fe78bSCy Schubert &pszProtSequence, &pszClientNetAddr,
665*7f2fe78bSCy Schubert NULL, NULL);
666*7f2fe78bSCy Schubert if (Status != RPC_S_OK)
667*7f2fe78bSCy Schubert __leave;
668*7f2fe78bSCy Schubert int iLen = lstrlen(pszClientName) + 1;
669*7f2fe78bSCy Schubert if (iMaxLen < iLen)
670*7f2fe78bSCy Schubert Status = RPC_S_BUFFER_TOO_SMALL;
671*7f2fe78bSCy Schubert lstrcpyn(pszClientName, (LPCTSTR)pszClientNetAddr, iMaxLen);
672*7f2fe78bSCy Schubert }
673*7f2fe78bSCy Schubert __finally {
674*7f2fe78bSCy Schubert if (pszProtSequence)
675*7f2fe78bSCy Schubert RpcStringFree (&pszProtSequence);
676*7f2fe78bSCy Schubert
677*7f2fe78bSCy Schubert if (pszClientNetAddr)
678*7f2fe78bSCy Schubert RpcStringFree (&pszClientNetAddr);
679*7f2fe78bSCy Schubert
680*7f2fe78bSCy Schubert if (pszStringBinding)
681*7f2fe78bSCy Schubert RpcStringFree (&pszStringBinding);
682*7f2fe78bSCy Schubert
683*7f2fe78bSCy Schubert if (hServer)
684*7f2fe78bSCy Schubert RpcBindingFree (&hServer);
685*7f2fe78bSCy Schubert }
686*7f2fe78bSCy Schubert return Status;
687*7f2fe78bSCy Schubert }
688*7f2fe78bSCy Schubert
689*7f2fe78bSCy Schubert struct client_auth_info {
690*7f2fe78bSCy Schubert RPC_AUTHZ_HANDLE authz_handle;
691*7f2fe78bSCy Schubert unsigned char* server_principal; // need to RpcFreeString this
692*7f2fe78bSCy Schubert ULONG authn_level;
693*7f2fe78bSCy Schubert ULONG authn_svc;
694*7f2fe78bSCy Schubert ULONG authz_svc;
695*7f2fe78bSCy Schubert };
696*7f2fe78bSCy Schubert
697*7f2fe78bSCy Schubert RPC_STATUS
GetClientId(RPC_BINDING_HANDLE hClient,char * client_id,int max_len,client_auth_info * info)698*7f2fe78bSCy Schubert GetClientId(
699*7f2fe78bSCy Schubert RPC_BINDING_HANDLE hClient,
700*7f2fe78bSCy Schubert char* client_id,
701*7f2fe78bSCy Schubert int max_len,
702*7f2fe78bSCy Schubert client_auth_info* info
703*7f2fe78bSCy Schubert )
704*7f2fe78bSCy Schubert {
705*7f2fe78bSCy Schubert RPC_AUTHZ_HANDLE authz_handle = 0;
706*7f2fe78bSCy Schubert unsigned char* server_principal = 0;
707*7f2fe78bSCy Schubert ULONG authn_level = 0;
708*7f2fe78bSCy Schubert ULONG authn_svc = 0;
709*7f2fe78bSCy Schubert ULONG authz_svc = 0;
710*7f2fe78bSCy Schubert RPC_STATUS status = 0;
711*7f2fe78bSCy Schubert
712*7f2fe78bSCy Schubert memset(client_id, 0, max_len);
713*7f2fe78bSCy Schubert
714*7f2fe78bSCy Schubert if (info) {
715*7f2fe78bSCy Schubert memset(info, 0, sizeof(client_auth_info));
716*7f2fe78bSCy Schubert }
717*7f2fe78bSCy Schubert
718*7f2fe78bSCy Schubert status = RpcBindingInqAuthClient(hClient, &authz_handle,
719*7f2fe78bSCy Schubert info ? &server_principal : 0,
720*7f2fe78bSCy Schubert &authn_level, &authn_svc, &authz_svc);
721*7f2fe78bSCy Schubert if (status == RPC_S_OK)
722*7f2fe78bSCy Schubert {
723*7f2fe78bSCy Schubert if (info) {
724*7f2fe78bSCy Schubert info->server_principal = server_principal;
725*7f2fe78bSCy Schubert info->authz_handle = authz_handle;
726*7f2fe78bSCy Schubert info->authn_level = authn_level;
727*7f2fe78bSCy Schubert info->authn_svc = authn_svc;
728*7f2fe78bSCy Schubert info->authz_svc = authz_svc;
729*7f2fe78bSCy Schubert }
730*7f2fe78bSCy Schubert
731*7f2fe78bSCy Schubert if (authn_svc == RPC_C_AUTHN_WINNT) {
732*7f2fe78bSCy Schubert WCHAR* username = (WCHAR*)authz_handle;
733*7f2fe78bSCy Schubert int len = lstrlenW(username) + 1;
734*7f2fe78bSCy Schubert if (max_len < len)
735*7f2fe78bSCy Schubert status = RPC_S_BUFFER_TOO_SMALL;
736*7f2fe78bSCy Schubert _snprintf(client_id, max_len, "%S", username);
737*7f2fe78bSCy Schubert } else {
738*7f2fe78bSCy Schubert status = RPC_S_UNKNOWN_AUTHN_SERVICE;
739*7f2fe78bSCy Schubert }
740*7f2fe78bSCy Schubert }
741*7f2fe78bSCy Schubert return status;
742*7f2fe78bSCy Schubert }
743*7f2fe78bSCy Schubert
744*7f2fe78bSCy Schubert char*
rpc_error_to_string(RPC_STATUS status)745*7f2fe78bSCy Schubert rpc_error_to_string(
746*7f2fe78bSCy Schubert RPC_STATUS status
747*7f2fe78bSCy Schubert )
748*7f2fe78bSCy Schubert {
749*7f2fe78bSCy Schubert switch(status) {
750*7f2fe78bSCy Schubert case RPC_S_OK:
751*7f2fe78bSCy Schubert return "OK";
752*7f2fe78bSCy Schubert case RPC_S_INVALID_BINDING:
753*7f2fe78bSCy Schubert return "Invalid binding";
754*7f2fe78bSCy Schubert case RPC_S_WRONG_KIND_OF_BINDING:
755*7f2fe78bSCy Schubert return "Wrong binding";
756*7f2fe78bSCy Schubert case RPC_S_BINDING_HAS_NO_AUTH:
757*7f2fe78bSCy Schubert RpcRaiseException(RPC_S_BINDING_HAS_NO_AUTH);
758*7f2fe78bSCy Schubert return "Binding has no auth";
759*7f2fe78bSCy Schubert default:
760*7f2fe78bSCy Schubert return "BUG: I am confused";
761*7f2fe78bSCy Schubert }
762*7f2fe78bSCy Schubert }
763*7f2fe78bSCy Schubert
764*7f2fe78bSCy Schubert void
print_client_info(RPC_STATUS peer_status,const char * peer_name,RPC_STATUS client_status,const char * client_id,client_auth_info * info)765*7f2fe78bSCy Schubert print_client_info(
766*7f2fe78bSCy Schubert RPC_STATUS peer_status,
767*7f2fe78bSCy Schubert const char* peer_name,
768*7f2fe78bSCy Schubert RPC_STATUS client_status,
769*7f2fe78bSCy Schubert const char* client_id,
770*7f2fe78bSCy Schubert client_auth_info* info
771*7f2fe78bSCy Schubert )
772*7f2fe78bSCy Schubert {
773*7f2fe78bSCy Schubert if (peer_status == RPC_S_OK || peer_status == RPC_S_BUFFER_TOO_SMALL) {
774*7f2fe78bSCy Schubert cci_debug_printf("%s Peer Name is \"%s\"", __FUNCTION__, peer_name);
775*7f2fe78bSCy Schubert } else {
776*7f2fe78bSCy Schubert cci_debug_printf("%s Error %u getting Peer Name (%s)",
777*7f2fe78bSCy Schubert __FUNCTION__, peer_status, rpc_error_to_string(peer_status));
778*7f2fe78bSCy Schubert }
779*7f2fe78bSCy Schubert
780*7f2fe78bSCy Schubert if (client_status == RPC_S_OK || client_status == RPC_S_BUFFER_TOO_SMALL) {
781*7f2fe78bSCy Schubert if (info) {
782*7f2fe78bSCy Schubert cci_debug_printf("%s Client Auth Info"
783*7f2fe78bSCy Schubert "\tServer Principal: %s\n"
784*7f2fe78bSCy Schubert "\tAuthentication Level: %d\n"
785*7f2fe78bSCy Schubert "\tAuthentication Service: %d\n"
786*7f2fe78bSCy Schubert "\tAuthorization Service: %d\n",
787*7f2fe78bSCy Schubert __FUNCTION__,
788*7f2fe78bSCy Schubert info->server_principal,
789*7f2fe78bSCy Schubert info->authn_level,
790*7f2fe78bSCy Schubert info->authn_svc,
791*7f2fe78bSCy Schubert info->authz_svc);
792*7f2fe78bSCy Schubert }
793*7f2fe78bSCy Schubert cci_debug_printf("%s Client ID is \"%s\"", __FUNCTION__, client_id);
794*7f2fe78bSCy Schubert } else {
795*7f2fe78bSCy Schubert cci_debug_printf("%s Error getting Client Info (%u = %s)",
796*7f2fe78bSCy Schubert __FUNCTION__, client_status, rpc_error_to_string(client_status));
797*7f2fe78bSCy Schubert }
798*7f2fe78bSCy Schubert }
799*7f2fe78bSCy Schubert
sid_check()800*7f2fe78bSCy Schubert DWORD sid_check() {
801*7f2fe78bSCy Schubert DWORD status = 0;
802*7f2fe78bSCy Schubert HANDLE hToken_c = 0;
803*7f2fe78bSCy Schubert HANDLE hToken_s = 0;
804*7f2fe78bSCy Schubert PTOKEN_USER ptu_c = 0;
805*7f2fe78bSCy Schubert PTOKEN_USER ptu_s = 0;
806*7f2fe78bSCy Schubert DWORD len = 0;
807*7f2fe78bSCy Schubert BOOL bImpersonate = FALSE;
808*7f2fe78bSCy Schubert
809*7f2fe78bSCy Schubert // Note GetUserName will fail while impersonating at identify
810*7f2fe78bSCy Schubert // level. The workaround is to impersonate, OpenThreadToken,
811*7f2fe78bSCy Schubert // revert, call GetTokenInformation, and finally, call
812*7f2fe78bSCy Schubert // LookupAccountSid.
813*7f2fe78bSCy Schubert
814*7f2fe78bSCy Schubert // XXX - Note: This workaround does not appear to work.
815*7f2fe78bSCy Schubert // OpenThreadToken fails with error 1346: "Either a requid
816*7f2fe78bSCy Schubert // impersonation level was not provided or the provided
817*7f2fe78bSCy Schubert // impersonation level is invalid".
818*7f2fe78bSCy Schubert
819*7f2fe78bSCy Schubert status = RpcImpersonateClient(0);
820*7f2fe78bSCy Schubert
821*7f2fe78bSCy Schubert if (!status) {
822*7f2fe78bSCy Schubert bImpersonate = TRUE;
823*7f2fe78bSCy Schubert if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken_c))
824*7f2fe78bSCy Schubert status = GetLastError();
825*7f2fe78bSCy Schubert }
826*7f2fe78bSCy Schubert
827*7f2fe78bSCy Schubert if (!status) {
828*7f2fe78bSCy Schubert status = RpcRevertToSelf();
829*7f2fe78bSCy Schubert }
830*7f2fe78bSCy Schubert
831*7f2fe78bSCy Schubert if (!status) {
832*7f2fe78bSCy Schubert bImpersonate = FALSE;
833*7f2fe78bSCy Schubert
834*7f2fe78bSCy Schubert len = 0;
835*7f2fe78bSCy Schubert GetTokenInformation(hToken_c, TokenUser, ptu_c, 0, &len);
836*7f2fe78bSCy Schubert if (len == 0) status = 1;
837*7f2fe78bSCy Schubert }
838*7f2fe78bSCy Schubert
839*7f2fe78bSCy Schubert if (!status) {
840*7f2fe78bSCy Schubert if (!(ptu_c = (PTOKEN_USER)LocalAlloc(0, len)))
841*7f2fe78bSCy Schubert status = GetLastError();
842*7f2fe78bSCy Schubert }
843*7f2fe78bSCy Schubert
844*7f2fe78bSCy Schubert if (!status) {
845*7f2fe78bSCy Schubert if (!GetTokenInformation(hToken_c, TokenUser, ptu_c, len, &len))
846*7f2fe78bSCy Schubert status = GetLastError();
847*7f2fe78bSCy Schubert }
848*7f2fe78bSCy Schubert
849*7f2fe78bSCy Schubert if (!status) {
850*7f2fe78bSCy Schubert if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken_s))
851*7f2fe78bSCy Schubert status = GetLastError();
852*7f2fe78bSCy Schubert }
853*7f2fe78bSCy Schubert
854*7f2fe78bSCy Schubert if (!status) {
855*7f2fe78bSCy Schubert len = 0;
856*7f2fe78bSCy Schubert GetTokenInformation(hToken_s, TokenUser, ptu_s, 0, &len);
857*7f2fe78bSCy Schubert if (len == 0) status = GetLastError();
858*7f2fe78bSCy Schubert }
859*7f2fe78bSCy Schubert
860*7f2fe78bSCy Schubert if (!status) {
861*7f2fe78bSCy Schubert if (!(ptu_s = (PTOKEN_USER)LocalAlloc(0, len)))
862*7f2fe78bSCy Schubert status = GetLastError();
863*7f2fe78bSCy Schubert }
864*7f2fe78bSCy Schubert
865*7f2fe78bSCy Schubert if (!status) {
866*7f2fe78bSCy Schubert if (!GetTokenInformation(hToken_s, TokenUser, ptu_s, len, &len))
867*7f2fe78bSCy Schubert status = GetLastError();
868*7f2fe78bSCy Schubert }
869*7f2fe78bSCy Schubert
870*7f2fe78bSCy Schubert if (!EqualSid(ptu_s->User.Sid, ptu_c->User.Sid))
871*7f2fe78bSCy Schubert status = RPC_S_ACCESS_DENIED;
872*7f2fe78bSCy Schubert
873*7f2fe78bSCy Schubert /* Cleanup: */
874*7f2fe78bSCy Schubert if (!hToken_c && !bImpersonate)
875*7f2fe78bSCy Schubert cci_debug_printf("%s Cannot impersonate (%u)", __FUNCTION__, status);
876*7f2fe78bSCy Schubert else if (!hToken_c)
877*7f2fe78bSCy Schubert cci_debug_printf("%s Failed to open client token (%u)", __FUNCTION__, status);
878*7f2fe78bSCy Schubert else if (bImpersonate)
879*7f2fe78bSCy Schubert cci_debug_printf("%s Failed to revert (%u)", __FUNCTION__, status);
880*7f2fe78bSCy Schubert else if (!ptu_c)
881*7f2fe78bSCy Schubert cci_debug_printf("%s Failed to get client token user info (%u)",
882*7f2fe78bSCy Schubert __FUNCTION__, status);
883*7f2fe78bSCy Schubert else if (!hToken_s)
884*7f2fe78bSCy Schubert cci_debug_printf("%s Failed to open server token (%u)", __FUNCTION__, status);
885*7f2fe78bSCy Schubert else if (!ptu_s)
886*7f2fe78bSCy Schubert cci_debug_printf("%s Failed to get server token user info (%u)",
887*7f2fe78bSCy Schubert __FUNCTION__, status);
888*7f2fe78bSCy Schubert else if (status == RPC_S_ACCESS_DENIED)
889*7f2fe78bSCy Schubert cci_debug_printf("%s SID **does not** match!", __FUNCTION__);
890*7f2fe78bSCy Schubert else if (status == RPC_S_OK)
891*7f2fe78bSCy Schubert cci_debug_printf("%s SID matches!", __FUNCTION__);
892*7f2fe78bSCy Schubert else
893*7f2fe78bSCy Schubert if (status) {
894*7f2fe78bSCy Schubert cci_debug_printf("%s unrecognized error %u", __FUNCTION__, status);
895*7f2fe78bSCy Schubert abort();
896*7f2fe78bSCy Schubert }
897*7f2fe78bSCy Schubert
898*7f2fe78bSCy Schubert if (bImpersonate) RpcRevertToSelf();
899*7f2fe78bSCy Schubert if (hToken_c && hToken_c != INVALID_HANDLE_VALUE)
900*7f2fe78bSCy Schubert CloseHandle(hToken_c);
901*7f2fe78bSCy Schubert if (ptu_c) LocalFree(ptu_c);
902*7f2fe78bSCy Schubert if (hToken_s && hToken_s != INVALID_HANDLE_VALUE)
903*7f2fe78bSCy Schubert CloseHandle(hToken_s);
904*7f2fe78bSCy Schubert if (ptu_s) LocalFree(ptu_s);
905*7f2fe78bSCy Schubert if (status) cci_debug_printf("%s returning %u", __FUNCTION__, status);
906*7f2fe78bSCy Schubert return status;
907*7f2fe78bSCy Schubert }
908*7f2fe78bSCy Schubert
sec_callback(IN RPC_IF_ID * Interface,IN void * Context)909*7f2fe78bSCy Schubert RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface,
910*7f2fe78bSCy Schubert IN void *Context) {
911*7f2fe78bSCy Schubert char peer_name[1024];
912*7f2fe78bSCy Schubert char client_name[1024];
913*7f2fe78bSCy Schubert RPC_STATUS peer_status;
914*7f2fe78bSCy Schubert RPC_STATUS client_status;
915*7f2fe78bSCy Schubert
916*7f2fe78bSCy Schubert cci_debug_printf("%s", __FUNCTION__);
917*7f2fe78bSCy Schubert peer_status = GetPeerName(Context, peer_name, sizeof(peer_name));
918*7f2fe78bSCy Schubert client_status = GetClientId(Context, client_name, sizeof(client_name), 0);
919*7f2fe78bSCy Schubert print_client_info(peer_status, peer_name, client_status, client_name, 0);
920*7f2fe78bSCy Schubert DWORD sid_status = sid_check();
921*7f2fe78bSCy Schubert cci_debug_printf("%s returning (%u)", __FUNCTION__, sid_status);
922*7f2fe78bSCy Schubert return sid_status;
923*7f2fe78bSCy Schubert }
924*7f2fe78bSCy Schubert
925*7f2fe78bSCy Schubert
926*7f2fe78bSCy Schubert
927*7f2fe78bSCy Schubert /*********************************************************************/
928*7f2fe78bSCy Schubert /* MIDL allocate and free */
929*7f2fe78bSCy Schubert /*********************************************************************/
930*7f2fe78bSCy Schubert
midl_user_allocate(size_t len)931*7f2fe78bSCy Schubert extern "C" void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) {
932*7f2fe78bSCy Schubert return(malloc(len));
933*7f2fe78bSCy Schubert }
934*7f2fe78bSCy Schubert
midl_user_free(void __RPC_FAR * ptr)935*7f2fe78bSCy Schubert extern "C" void __RPC_USER midl_user_free(void __RPC_FAR * ptr) {
936*7f2fe78bSCy Schubert free(ptr);
937*7f2fe78bSCy Schubert }
938*7f2fe78bSCy Schubert
939*7f2fe78bSCy Schubert /* stubs */
940*7f2fe78bSCy Schubert extern "C" cc_int32
ccs_os_notify_cache_collection_changed(ccs_cache_collection_t cc)941*7f2fe78bSCy Schubert ccs_os_notify_cache_collection_changed (ccs_cache_collection_t cc)
942*7f2fe78bSCy Schubert {
943*7f2fe78bSCy Schubert return 0;
944*7f2fe78bSCy Schubert }
945*7f2fe78bSCy Schubert
946*7f2fe78bSCy Schubert extern "C" cc_int32
ccs_os_notify_ccache_changed(ccs_cache_collection_t cc,const char * name)947*7f2fe78bSCy Schubert ccs_os_notify_ccache_changed (ccs_cache_collection_t cc, const char *name)
948*7f2fe78bSCy Schubert {
949*7f2fe78bSCy Schubert return 0;
950*7f2fe78bSCy Schubert }
951