xref: /freebsd/crypto/krb5/src/ccapi/server/win/ccs_os_server.cpp (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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