4 * Copyright 2008 Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
31 #include "ccs_common.h"
32 #include "ccs_os_notify.h"
33 #include "ccs_os_server.h"
34 #include "ccs_reply.h"
35 #include "ccs_request.h"
36 #include "win-utils.h"
40 #include "WorkQueue.h"
45 #pragma warning (disable : 4996)
47 BOOL bListen = TRUE; /* Why aren't bool and true defined? */
48 const char* sessID = NULL; /* The logon session we are running on behalf of. */
50 unsigned char* pszNetworkAddress = NULL;
51 unsigned char* pszStringBinding = NULL;
52 BOOL bRpcHandleInited = FALSE;
53 _RPC_ASYNC_STATE* rpcState = NULL;
55 /* Thread procedures can take only one void* argument. We put all the args we want
56 to pass into this struct and then pass a pointer to the struct: */
59 unsigned char* protocolSequence;
60 unsigned char* sessID; /* Used for this server's endpoint */
61 unsigned char* uuid; /* Used for client's UUID */
62 ParseOpts::Opts* opts;
64 } rpcargs = { NULL, /* pszNetworkAddress */
65 (unsigned char*)"ncalrpc", /* pszProtocolSequence */
66 NULL, /* sessID placeholder */
67 NULL, /* uuid placeholder */
68 NULL }; /* Opts placeholder */
70 /* Command line format:
72 argv[1] session ID to use
73 argv[2] "D" Debug: go into infinite loop in ccs_os_server_initialize so process
74 can be attached in debugger.
75 Any other value: continue
77 #define N_FIXED_ARGS 3
78 #define SERVER_REPLY_RPC_HANDLE ccs_reply_IfHandle
80 /* Forward declarations: */
81 void receiveLoop(void* rpcargs);
82 void connectionListener(void* rpcargs);
83 void Usage(const char* argv0);
84 void printError(TCHAR* msg);
85 void setMySST() {_sst = time(&_sst);}
86 time_t getMySST() {return _sst;}
87 RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe);
88 void RPC_ENTRY clientListener( _RPC_ASYNC_STATE*,
90 RPC_ASYNC_EVENT Event);
91 RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface,
93 RPC_STATUS send_init(char* clientUUID);
94 //DWORD alloc_name(LPSTR* pname, LPSTR postfix);
97 /* The layout of the rest of this module:
99 The four entrypoints defined in ccs_os_server.h:
100 ccs_os_server_initialize
101 cc_int32 ccs_os_server_cleanup
102 cc_int32 ccs_os_server_listen_loop
103 cc_int32 ccs_os_server_send_reply
105 Other routines needed by those four.
108 /* ------------------------------------------------------------------------ */
110 cc_int32 ccs_os_server_initialize (int argc, const char *argv[]) {
112 ParseOpts::Opts opts = { 0 };
114 BOOL bAdjustedShutdown = FALSE;
115 HMODULE hKernel32 = GetModuleHandle("kernel32");
123 opts.fDontWait = TRUE;
125 #ifdef CCAPI_TEST_OPTIONS
126 PO.SetValidOpts("kemnfubc");
128 PO.SetValidOpts("kc");
131 PO.Parse(opts, argc, (char**)argv);
133 // while(*argv[2] == 'D') {} /* Hang here to attach process with debugger. */
136 typedef BOOL (WINAPI *FP_SetProcessShutdownParameters)(DWORD, DWORD);
137 FP_SetProcessShutdownParameters pSetProcessShutdownParameters =
138 (FP_SetProcessShutdownParameters)
139 GetProcAddress(hKernel32, "SetProcessShutdownParameters");
140 if (pSetProcessShutdownParameters) {
141 bAdjustedShutdown = pSetProcessShutdownParameters(100, 0);
144 cci_debug_printf("%s Shutdown Parameters",
145 bAdjustedShutdown ? "Adjusted" : "Did not adjust");
147 err = Init::Initialize();
151 // if (opts.bShutdown) {
152 // status = shutdown_server(opts.pszEndpoint);
156 // status = startup_server(opts);
160 err = worklist_initialize();
165 fprintf( stderr, "An error occured while %s the server (%u)\n",
166 opts.bShutdown ? "shutting down" : "starting/running",
168 exit(cci_check_error (err));
171 return cci_check_error (err);
174 /* ------------------------------------------------------------------------ */
176 cc_int32 ccs_os_server_cleanup (int argc, const char *argv[]) {
179 cci_debug_printf("%s for user <%s> shutting down.", argv[0], argv[1]);
183 return cci_check_error (err);
186 /* ------------------------------------------------------------------------ */
188 /* This function takes work items off the work queue and executes them.
189 * This is the one and only place where the multi-threaded Windows code
190 * calls into the single-threaded common code.
192 * The actual 'listening' for requests from clients happens after receiveloop
193 * establishes the RPC endpoint the clients will connect to and the RPC procedures
194 * put the work items into the work queue.
196 cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[]) {
198 uintptr_t threadStatus;
200 ParseOpts::Opts opts = { 0 };
202 BOOL bQuitIfNoClients = FALSE;
206 opts.fDontWait = TRUE;
208 #ifdef CCAPI_TEST_OPTIONS
209 PO.SetValidOpts("kemnfubc");
211 PO.SetValidOpts("kc");
213 PO.Parse(opts, argc, (char**)argv);
217 #define INFO_BUFFER_SIZE 32767
218 TCHAR infoBuf[INFO_BUFFER_SIZE];
219 DWORD bufCharCount = INFO_BUFFER_SIZE;
220 // Get and display the user name.
221 bufCharCount = INFO_BUFFER_SIZE;
222 if( !GetUserName( infoBuf, &bufCharCount ) ) printError( TEXT("GetUserName") );
225 /* Sending the reply from within the request RPC handler doesn't seem to work.
226 So we listen for requests in a separate thread and put the requests in a
228 rpcargs.sessID = (unsigned char*)sessID;
229 rpcargs.opts = &opts;
230 /// TODO: check for NULL handle, error, etc. probably move to initialize func...
231 threadStatus = _beginthread(receiveLoop, 0, (void*)&rpcargs);
233 /* We handle the queue entries here. Work loop: */
234 while (ccs_server_client_count() > 0 || !bQuitIfNoClients) {
236 while (!worklist_isEmpty()) {
237 k5_ipc_stream buf = NULL;
238 long rpcmsg = CCMSG_INVALID;
239 time_t serverStartTime = 0xDEADDEAD;
240 RPC_STATUS status = 0;
242 k5_ipc_stream stream = NULL;
243 ccs_pipe_t pipe = NULL;
244 ccs_pipe_t pipe2 = NULL;
246 if (worklist_remove(&rpcmsg, &pipe, &buf, &serverStartTime)) {
247 uuid = ccs_win_pipe_getUuid(pipe);
249 cci_debug_printf("%s: processing WorkItem msg:%ld pipeUUID:<%s> pipeHandle:0x%X SST:%ld",
250 __FUNCTION__, rpcmsg, uuid, ccs_win_pipe_getHandle(pipe), serverStartTime);
252 if (serverStartTime <= getMySST()) {
254 case CCMSG_CONNECT: {
255 cci_debug_printf(" Processing CONNECT");
256 rpcargs.uuid = (unsigned char*)uuid;
258 // Even if a disconnect message is received before this code finishes,
259 // it won't be dequeued and processed until after this code finishes.
260 // So we can add the client after starting the connection listener.
261 connectionListener((void*)&rpcargs);
262 status = rpcargs.status;
265 status = ccs_server_add_client(pipe);
267 if (!status) {status = send_connection_reply(pipe);}
270 case CCMSG_DISCONNECT: {
271 cci_debug_printf(" Processing DISCONNECT");
273 status = ccs_server_remove_client(pipe);
278 cci_debug_printf(" Processing REQUEST");
279 ccs_pipe_copy(&pipe2, pipe);
280 // Dispatch message here, setting both pipes to the client UUID:
281 err = ccs_server_handle_request (pipe, pipe2, buf);
284 cci_debug_printf(" Processing PING");
285 err = krb5int_ipc_stream_new (&stream);
286 err = krb5int_ipc_stream_write(stream, "This is a test of the emergency broadcasting system", 52);
287 err = ccs_os_server_send_reply(pipe, stream);
290 bQuitIfNoClients = TRUE;
293 cci_debug_printf("Huh? Received invalid message type %ld from UUID:<%s>",
297 if (buf) krb5int_ipc_stream_release(buf);
298 /* Don't free uuid, which was allocated here. A pointer to it is in the
299 rpcargs struct which was passed to connectionListener which will be
300 received by ccapi_listen when the client exits. ccapi_listen needs
301 the uuid to know which client to disconnect.
304 // Server's start time is different from what the client thinks.
305 // That means the server has rebooted since the client connected.
307 cci_debug_printf("Whoops! Server has rebooted since client established connection.");
310 else {cci_debug_printf("Huh? Queue not empty but no item to remove.");}
313 return cci_check_error (err);
316 /* ------------------------------------------------------------------------ */
318 cc_int32 ccs_os_server_send_reply (ccs_pipe_t in_pipe,
319 k5_ipc_stream in_reply_stream) {
321 /* ccs_pipe_t in_reply_pipe is a char* reply endpoint.
322 k5_ipc_stream in_reply_stream is the data to be sent.
326 char* uuid = ccs_win_pipe_getUuid(in_pipe);
327 UINT64 h = ccs_win_pipe_getHandle(in_pipe);
330 err = send_init(uuid); // Sets RPC handle to be used.
336 ccs_rpc_request_reply( // make call with user message
337 CCMSG_REQUEST_REPLY, /* Message type */
338 (unsigned char*)&h, /* client's tspdata* */
339 (unsigned char*)uuid,
341 krb5int_ipc_stream_size(in_reply_stream), /* Length of buffer */
342 (const unsigned char*)krb5int_ipc_stream_data(in_reply_stream), /* Data buffer */
343 &status ); /* Return code */
346 cci_check_error(RpcExceptionCode());
351 /* The calls to the remote procedures are complete. */
352 /* Free whatever we allocated: */
353 err = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE);
355 return cci_check_error (err);
359 /* Windows-specific routines: */
361 void Usage(const char* argv0) {
363 printf("%s [m maxcalls] [n mincalls] [f dontwait] [h|?]]\n", argv0);
364 printf(" CCAPI server process.\n");
365 printf(" h|? whow usage message. <\n");
368 /* ------------------------------------------------------------------------ */
369 /* The receive thread repeatedly issues RpcServerListen.
370 When a message arrives, it is handled in the RPC procedure.
372 void receiveLoop(void* rpcargs) {
374 struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs;
375 RPC_STATUS status = FALSE;
376 unsigned char* pszSecurity = NULL;
377 LPSTR endpoint = NULL;
378 LPSTR event_name = NULL;
379 PSECURITY_DESCRIPTOR psd = NULL;
383 cci_debug_printf("THREAD BEGIN: %s", __FUNCTION__);
385 status = Init::Info(info);
387 /* Build complete RPC endpoint using previous CCAPI implementation: */
389 if (!rcvargs->opts->pszEndpoint) {
391 status = alloc_name(&endpoint, "ep", isNT());
395 status = alloc_name(&event_name, "startup", isNT());
399 hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name);
400 // We ignore any error opening the event because we do not know who started us.
401 // [Comment paraphrased from previous implementation, whence it was copied.]
405 endpoint = rcvargs->opts->pszEndpoint;
409 cci_debug_printf("%s Registering endpoint %s", __FUNCTION__, endpoint);
411 if (!status && isNT()) {
412 status = alloc_own_security_descriptor_NT(&psd);
416 status = RpcServerUseProtseqEp(rcvargs->protocolSequence,
417 rcvargs->opts->cMaxCalls,
419 rcvargs->opts->bDontProtect ? 0 : psd); // SD
423 status = RpcServerRegisterAuthInfo(0, // server principal
429 while (bListen && !status) {
430 cci_debug_printf("%s is listening ...", __FUNCTION__);
433 status = RpcServerRegisterIf(ccs_request_ServerIfHandle, // interface
435 NULL); // MgrEpv; null means use default
438 status = info.fRpcServerRegisterIfEx(ccs_request_ServerIfHandle, // interface
440 NULL, // MgrEpv; 0 means default
441 RPC_IF_ALLOW_SECURE_ONLY,
442 rcvargs->opts->cMaxCalls,
443 rcvargs->opts->bSecCallback ?
444 (RPC_IF_CALLBACK_FN*)sec_callback : 0 );
448 status = RpcServerListen(rcvargs->opts->cMinCalls,
449 rcvargs->opts->cMaxCalls,
450 rcvargs->opts->fDontWait);
454 if (rcvargs->opts->fDontWait) {
455 if (hEvent) SetEvent(hEvent); // Ignore any error -- SetEvent is an optimization.
456 status = RpcMgmtWaitServerListen();
461 if (status) { // Cleanup in case of errors:
462 if (hEvent) CloseHandle(hEvent);
463 free_alloc_p(&event_name);
465 if (endpoint && (endpoint != rcvargs->opts->pszEndpoint))
466 free_alloc_p(&endpoint);
469 // tell main thread to shutdown since it won't receive any more messages
470 worklist_add(CCMSG_QUIT, NULL, NULL, 0);
483 /* ------------------------------------------------------------------------ */
484 /* The connection listener thread waits forever for a call to the CCAPI_CLIENT_<UUID>
485 endpoint, ccapi_listen function to complete. If the call completes or gets an
486 RPC exception, it means the client has disappeared.
488 A separate connectionListener is started for each client that has connected to the server.
491 void connectionListener(void* rpcargs) {
493 struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs;
494 RPC_STATUS status = FALSE;
496 unsigned char* pszOptions = NULL;
497 unsigned char * pszUuid = NULL;
499 endpoint = clientEndpoint((char*)rcvargs->uuid);
500 rpcState = (RPC_ASYNC_STATE*)malloc(sizeof(RPC_ASYNC_STATE));
501 status = RpcAsyncInitializeHandle(rpcState, sizeof(RPC_ASYNC_STATE));
502 cci_debug_printf("");
503 cci_debug_printf("%s About to LISTEN to <%s>", __FUNCTION__, endpoint);
505 rpcState->UserInfo = rcvargs->uuid;
506 rpcState->NotificationType = RpcNotificationTypeApc;
507 rpcState->u.APC.NotificationRoutine = clientListener;
508 rpcState->u.APC.hThread = 0;
510 /* [If in use] Free previous binding: */
511 if (bRpcHandleInited) {
512 // Free previous binding (could have been used to call ccapi_listen
513 // in a different client thread).
514 // Don't check result or update status.
515 RpcStringFree(&pszStringBinding);
516 RpcBindingFree(&SERVER_REPLY_RPC_HANDLE);
517 bRpcHandleInited = FALSE;
520 /* Set up binding to the client's endpoint: */
522 status = RpcStringBindingCompose(
531 /* Set the binding handle that will be used to bind to the server. */
533 status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE);
535 if (!status) {bRpcHandleInited = TRUE;}
538 cci_debug_printf(" Calling remote procedure ccapi_listen");
539 ccapi_listen(rpcState, SERVER_REPLY_RPC_HANDLE, CCMSG_LISTEN, &status);
540 /* Asynchronous call will return immediately. */
543 status = cci_check_error(RpcExceptionCode());
547 rcvargs->status = status;
548 } // End connectionListener
551 void RPC_ENTRY clientListener(
552 _RPC_ASYNC_STATE* pAsync,
554 RPC_ASYNC_EVENT Event
557 ccs_pipe_t pipe = ccs_win_pipe_new((char*)pAsync->UserInfo, NULL);
559 cci_debug_printf("%s(0x%X, ...) async routine for <0x%X:%s>!",
560 __FUNCTION__, pAsync, pAsync->UserInfo, pAsync->UserInfo);
562 worklist_add( CCMSG_DISCONNECT,
564 NULL, /* No payload with connect request */
565 (const time_t)0 ); /* No server session number with connect request */
569 void printError( TCHAR* msg ) {
574 eNum = GetLastError( );
575 FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
576 FORMAT_MESSAGE_IGNORE_INSERTS,
578 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
581 // Trim the end of the line and terminate it with a null
583 while( ( *p > 31 ) || ( *p == 9 ) )
585 do { *p-- = 0; } while( ( p >= sysMsg ) &&
586 ( ( *p == '.' ) || ( *p < 33 ) ) );
588 // Display the message
589 cci_debug_printf("%s failed with error %d (%s)", msg, eNum, sysMsg);
593 RPC_STATUS send_init(char* clientUUID) {
595 unsigned char * pszUuid = NULL;
596 unsigned char * pszOptions = NULL;
598 /* Use a convenience function to concatenate the elements of */
599 /* the string binding into the proper sequence. */
600 status = RpcStringBindingCompose(pszUuid,
603 (unsigned char*)clientEndpoint(clientUUID),
606 if (status) {return (status);}
608 /* Set the binding handle that will be used to bind to the RPC server [the 'client']. */
609 status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE);
613 RPC_STATUS send_finish() {
615 /* Can't shut down client -- it runs listen function which */
616 /* server uses to detect the client going away. */
618 /* The calls to the remote procedures are complete. */
619 /* Free the string and the binding handle */
620 status = RpcStringFree(&pszStringBinding); // remote calls done; unbind
621 if (status) {return (status);}
623 status = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); // remote calls done; unbind
628 RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe) {
629 char* uuid = ccs_win_pipe_getUuid (in_pipe);
630 UINT64 h = ccs_win_pipe_getHandle(in_pipe);
631 RPC_STATUS status = send_init(uuid);
634 ccs_rpc_connect_reply( // make call with user message
635 CCMSG_CONNECT_REPLY, /* Message type */
636 (unsigned char*)&h, /* client's tspdata* */
637 (unsigned char*)uuid,
638 getMySST(), /* Server's session number = it's start time */
639 &status ); /* Return code */
642 cci_check_error(RpcExceptionCode());
646 status = send_finish();
651 DWORD alloc_name(LPSTR* pname, LPSTR postfix) {
652 DWORD len = strlen(sessID) + 1 + strlen(postfix) + 1;
654 *pname = (LPSTR)malloc(len);
655 if (!*pname) return GetLastError();
656 _snprintf(*pname, len, "%s.%s", sessID, postfix);
661 RPC_STATUS GetPeerName( RPC_BINDING_HANDLE hClient,
662 LPTSTR pszClientName,
664 RPC_STATUS Status = RPC_S_OK;
665 RPC_BINDING_HANDLE hServer = NULL;
666 PTBYTE pszStringBinding = NULL;
667 PTBYTE pszClientNetAddr = NULL;
668 PTBYTE pszProtSequence = NULL;
670 memset(pszClientName, 0, iMaxLen * sizeof(TCHAR));
673 // Create a partially bound server handle from the client handle.
674 Status = RpcBindingServerFromClient (hClient, &hServer);
675 if (Status != RPC_S_OK) __leave;
677 // Get the partially bound server string binding and parse it.
678 Status = RpcBindingToStringBinding (hServer,
680 if (Status != RPC_S_OK) __leave;
682 // String binding only contains protocol sequence and client
683 // address, and is not currently implemented for named pipes.
684 Status = RpcStringBindingParse (pszStringBinding, NULL,
685 &pszProtSequence, &pszClientNetAddr,
687 if (Status != RPC_S_OK)
689 int iLen = lstrlen(pszClientName) + 1;
691 Status = RPC_S_BUFFER_TOO_SMALL;
692 lstrcpyn(pszClientName, (LPCTSTR)pszClientNetAddr, iMaxLen);
696 RpcStringFree (&pszProtSequence);
698 if (pszClientNetAddr)
699 RpcStringFree (&pszClientNetAddr);
701 if (pszStringBinding)
702 RpcStringFree (&pszStringBinding);
705 RpcBindingFree (&hServer);
710 struct client_auth_info {
711 RPC_AUTHZ_HANDLE authz_handle;
712 unsigned char* server_principal; // need to RpcFreeString this
720 RPC_BINDING_HANDLE hClient,
723 client_auth_info* info
726 RPC_AUTHZ_HANDLE authz_handle = 0;
727 unsigned char* server_principal = 0;
728 ULONG authn_level = 0;
731 RPC_STATUS status = 0;
733 memset(client_id, 0, max_len);
736 memset(info, 0, sizeof(client_auth_info));
739 status = RpcBindingInqAuthClient(hClient, &authz_handle,
740 info ? &server_principal : 0,
741 &authn_level, &authn_svc, &authz_svc);
742 if (status == RPC_S_OK)
745 info->server_principal = server_principal;
746 info->authz_handle = authz_handle;
747 info->authn_level = authn_level;
748 info->authn_svc = authn_svc;
749 info->authz_svc = authz_svc;
752 if (authn_svc == RPC_C_AUTHN_WINNT) {
753 WCHAR* username = (WCHAR*)authz_handle;
754 int len = lstrlenW(username) + 1;
756 status = RPC_S_BUFFER_TOO_SMALL;
757 _snprintf(client_id, max_len, "%S", username);
759 status = RPC_S_UNKNOWN_AUTHN_SERVICE;
773 case RPC_S_INVALID_BINDING:
774 return "Invalid binding";
775 case RPC_S_WRONG_KIND_OF_BINDING:
776 return "Wrong binding";
777 case RPC_S_BINDING_HAS_NO_AUTH:
778 RpcRaiseException(RPC_S_BINDING_HAS_NO_AUTH);
779 return "Binding has no auth";
781 return "BUG: I am confused";
787 RPC_STATUS peer_status,
788 const char* peer_name,
789 RPC_STATUS client_status,
790 const char* client_id,
791 client_auth_info* info
794 if (peer_status == RPC_S_OK || peer_status == RPC_S_BUFFER_TOO_SMALL) {
795 cci_debug_printf("%s Peer Name is \"%s\"", __FUNCTION__, peer_name);
797 cci_debug_printf("%s Error %u getting Peer Name (%s)",
798 __FUNCTION__, peer_status, rpc_error_to_string(peer_status));
801 if (client_status == RPC_S_OK || client_status == RPC_S_BUFFER_TOO_SMALL) {
803 cci_debug_printf("%s Client Auth Info"
804 "\tServer Principal: %s\n"
805 "\tAuthentication Level: %d\n"
806 "\tAuthentication Service: %d\n"
807 "\tAuthorization Service: %d\n",
809 info->server_principal,
814 cci_debug_printf("%s Client ID is \"%s\"", __FUNCTION__, client_id);
816 cci_debug_printf("%s Error getting Client Info (%u = %s)",
817 __FUNCTION__, client_status, rpc_error_to_string(client_status));
825 PTOKEN_USER ptu_c = 0;
826 PTOKEN_USER ptu_s = 0;
828 BOOL bImpersonate = FALSE;
830 // Note GetUserName will fail while impersonating at identify
831 // level. The workaround is to impersonate, OpenThreadToken,
832 // revert, call GetTokenInformation, and finally, call
835 // XXX - Note: This workaround does not appear to work.
836 // OpenThreadToken fails with error 1346: "Either a requid
837 // impersonation level was not provided or the provided
838 // impersonation level is invalid".
840 status = RpcImpersonateClient(0);
844 if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken_c))
845 status = GetLastError();
849 status = RpcRevertToSelf();
853 bImpersonate = FALSE;
856 GetTokenInformation(hToken_c, TokenUser, ptu_c, 0, &len);
857 if (len == 0) status = 1;
861 if (!(ptu_c = (PTOKEN_USER)LocalAlloc(0, len)))
862 status = GetLastError();
866 if (!GetTokenInformation(hToken_c, TokenUser, ptu_c, len, &len))
867 status = GetLastError();
871 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken_s))
872 status = GetLastError();
877 GetTokenInformation(hToken_s, TokenUser, ptu_s, 0, &len);
878 if (len == 0) status = GetLastError();
882 if (!(ptu_s = (PTOKEN_USER)LocalAlloc(0, len)))
883 status = GetLastError();
887 if (!GetTokenInformation(hToken_s, TokenUser, ptu_s, len, &len))
888 status = GetLastError();
891 if (!EqualSid(ptu_s->User.Sid, ptu_c->User.Sid))
892 status = RPC_S_ACCESS_DENIED;
895 if (!hToken_c && !bImpersonate)
896 cci_debug_printf("%s Cannot impersonate (%u)", __FUNCTION__, status);
898 cci_debug_printf("%s Failed to open client token (%u)", __FUNCTION__, status);
899 else if (bImpersonate)
900 cci_debug_printf("%s Failed to revert (%u)", __FUNCTION__, status);
902 cci_debug_printf("%s Failed to get client token user info (%u)",
903 __FUNCTION__, status);
905 cci_debug_printf("%s Failed to open server token (%u)", __FUNCTION__, status);
907 cci_debug_printf("%s Failed to get server token user info (%u)",
908 __FUNCTION__, status);
909 else if (status == RPC_S_ACCESS_DENIED)
910 cci_debug_printf("%s SID **does not** match!", __FUNCTION__);
911 else if (status == RPC_S_OK)
912 cci_debug_printf("%s SID matches!", __FUNCTION__);
915 cci_debug_printf("%s unrecognized error %u", __FUNCTION__, status);
919 if (bImpersonate) RpcRevertToSelf();
920 if (hToken_c && hToken_c != INVALID_HANDLE_VALUE)
921 CloseHandle(hToken_c);
922 if (ptu_c) LocalFree(ptu_c);
923 if (hToken_s && hToken_s != INVALID_HANDLE_VALUE)
924 CloseHandle(hToken_s);
925 if (ptu_s) LocalFree(ptu_s);
926 if (status) cci_debug_printf("%s returning %u", __FUNCTION__, status);
930 RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface,
932 char peer_name[1024];
933 char client_name[1024];
934 RPC_STATUS peer_status;
935 RPC_STATUS client_status;
937 cci_debug_printf("%s", __FUNCTION__);
938 peer_status = GetPeerName(Context, peer_name, sizeof(peer_name));
939 client_status = GetClientId(Context, client_name, sizeof(client_name), 0);
940 print_client_info(peer_status, peer_name, client_status, client_name, 0);
941 DWORD sid_status = sid_check();
942 cci_debug_printf("%s returning (%u)", __FUNCTION__, sid_status);
948 /*********************************************************************/
949 /* MIDL allocate and free */
950 /*********************************************************************/
952 extern "C" void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) {
956 extern "C" void __RPC_USER midl_user_free(void __RPC_FAR * ptr) {
962 ccs_os_notify_cache_collection_changed (ccs_cache_collection_t cc)
968 ccs_os_notify_ccache_changed (ccs_cache_collection_t cc, const char *name)