From 530043377ee6f39b9ca95c13f6260602e6fe7674 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Thu, 25 Nov 2010 20:28:30 +0000 Subject: Fix Windows build Repair the Windows build. Tested with the prepare-on-Unix method. Some specific changes include: * Removed the IPC finalizer (no longer used after r20787) from ccapi/lib/ccapi_ipc.c, as it was creating a difficult dependency chain for the pingtest build in ccapi/test. Also updated pingtest to use the k5_ipc_stream interfaces since cci_stream is gone. * Reverted the apparently non-functional r20277. * klist -V prints just "Kerberos for Windows", since it has no access to PACKAGE_NAME and PACKAGE_VERSION from autoconf. This should be addressed correctly. * krb5, telnet, gssftp, and NIM are removed from the build. * Some files had CRLFs; these were replaced with LFs and the svn:eol-style property set on the files. Otherwise the CRLFs became CRCRLFs after the zip transfer. * Windows does not have opendir/readdir, so added Windows code to prof_parse.c for includedir. Probable fodder for a libkrb5support portability shim. ticket: 6826 target_version: 1.9 tags: pullup git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24533 dc483132-0cff-0310-8789-dd5450dbe970 --- src/ccapi/server/win/Makefile.in | 218 ++-- src/ccapi/server/win/Server.sln | 40 +- src/ccapi/server/win/Server.vcproj | 454 ++++---- src/ccapi/server/win/WorkItem.cpp | 252 ++--- src/ccapi/server/win/WorkQueue.cpp | 122 +- src/ccapi/server/win/ccs_os_server.cpp | 1926 ++++++++++++++++---------------- 6 files changed, 1506 insertions(+), 1506 deletions(-) (limited to 'src/ccapi/server') diff --git a/src/ccapi/server/win/Makefile.in b/src/ccapi/server/win/Makefile.in index 3d8da6d22..36909b85e 100644 --- a/src/ccapi/server/win/Makefile.in +++ b/src/ccapi/server/win/Makefile.in @@ -1,109 +1,109 @@ -# makefile: Constructs the Kerberos for Windows CCAPI server. - -#BUILDTOP is krb5/src and is relative to krb5/src/ccapi/server/win, for making Makefile. -BUILDTOP=..\..\..\ -CCAPI = $(BUILDTOP)\CCAPI -CO = $(CCAPI)\common -COWIN = $(CCAPI)\common\win -CCUTIL = $(CCAPI)\common\win\OldCC -SRVDIR = $(CCAPI)\server -SRVWIN = $(SRVDIR)\win -POSIX = $(BUILDTOP)\lib\krb5\posix -SRCTMP = $(SRVWIN)\srctmp - -!if defined(KRB5_KFW_COMPILE) -KFWINC= /I$(BUILDTOP)\..\..\krbcc\include -!endif - -OBJS = $(OUTPRE)cci_array_internal.$(OBJEXT) \ - $(OUTPRE)cci_cred_union.$(OBJEXT) \ - $(OUTPRE)cci_debugging.$(OBJEXT) \ - $(OUTPRE)cci_identifier.$(OBJEXT) \ - $(OUTPRE)cci_message.$(OBJEXT) \ - $(OUTPRE)cci_os_debugging.$(OBJEXT) \ - $(OUTPRE)cci_os_identifier.$(OBJEXT) \ - $(OUTPRE)ccs_array.$(OBJEXT) \ - $(OUTPRE)ccs_cache_collection.$(OBJEXT) \ - $(OUTPRE)ccs_callback.$(OBJEXT) \ - $(OUTPRE)ccs_ccache.$(OBJEXT) \ - $(OUTPRE)ccs_ccache_iterator.$(OBJEXT) \ - $(OUTPRE)ccs_client.$(OBJEXT) \ - $(OUTPRE)ccs_credentials.$(OBJEXT) \ - $(OUTPRE)ccs_credentials_iterator.$(OBJEXT) \ - $(OUTPRE)ccs_list.$(OBJEXT) \ - $(OUTPRE)ccs_list_internal.$(OBJEXT) \ - $(OUTPRE)ccs_lock.$(OBJEXT) \ - $(OUTPRE)ccs_lock_state.$(OBJEXT) \ - $(OUTPRE)ccs_os_pipe.$(OBJEXT) \ - $(OUTPRE)ccs_os_server.$(OBJEXT) \ - $(OUTPRE)ccs_pipe.$(OBJEXT) \ - $(OUTPRE)ccs_reply_c.$(OBJEXT) \ - $(OUTPRE)ccs_request_proc.$(OBJEXT) \ - $(OUTPRE)ccs_server.$(OBJEXT) \ - $(OUTPRE)ccs_win_pipe.$(OBJEXT) \ - $(OUTPRE)ccs_request_s.$(OBJEXT) \ - $(OUTPRE)ccutils.$(OBJEXT) \ - $(OUTPRE)init.$(OBJEXT) \ - $(OUTPRE)opts.$(OBJEXT) \ - $(OUTPRE)secure.$(OBJEXT) \ - $(OUTPRE)tls.$(OBJEXT) \ - $(OUTPRE)util.$(OBJEXT) \ - $(OUTPRE)win-utils.$(OBJEXT) \ - $(OUTPRE)WorkItem.$(OBJEXT) \ - $(OUTPRE)WorkQueue.$(OBJEXT) - -##### Options - -# Because all the sources are pulled together into the temp directory SRCTMP, -# the only includes we need are to directories outside of ccapi. -LOCALINCLUDES = /I..\$(BUILDTOP) /I..\$(BUILDTOP)\include /I..\$(BUILDTOP)\include\krb5 $(KFWINC) \ - -I..\$(BUILDTOP)\util\et /I. -MIDLI = /I..\$(BUILDTOP)\include - -CPPFLAGS = $(CPPFLAGS) /EHsc -D_CRTAPI1=_cdecl -D_CRTAPI2=_cdecl -DWINVER=0x0501 \ --D_WIN32_WINNT=0x0501 -D_CRT_SECURE_NO_WARNINGS - -##### Linker -LINK = link -LIBS = ..\$(SLIB) rpcrt4.lib advapi32.lib ws2_32.lib user32.lib -LFLAGS = /nologo $(LOPTS) - - -all:: Makefile copysrc midl $(OUTPRE)ccapiserver.exe finish - -ccs_request.h ccs_request_c.c ccs_request_s.c : ccs_request.idl ccs_request.acf - midl $(MIDL_OPTIMIZATION) $(MIDLI) -oldnames -cpp_cmd $(CC) -cpp_opt "-E" \ - ccs_request.idl - -ccs_reply.h ccs_reply_c.c ccs_reply_s.c : ccs_reply.idl ccs_reply.acf - midl $(MIDL_OPTIMIZATION) $(MIDLI) -oldnames -cpp_cmd $(CC) -cpp_opt "-E" \ - ccs_reply.idl - -copysrc : - echo "Copying all sources needed to build ccapiserver.exe to $(SRCTMP)" - if NOT exist $(SRCTMP)\nul mkdir $(SRCTMP) - xcopy /D/Y $(CO)\*.* $(SRCTMP) - xcopy /D/Y $(COWIN)\*.* $(SRCTMP) - xcopy /D/Y $(CCUTIL)\*.* $(SRCTMP) - xcopy /D/Y $(SRVDIR)\*.* $(SRCTMP) - xcopy /D/Y $(SRVWIN)\*.* $(SRCTMP) - cd $(SRCTMP) - if NOT exist $(OUTPRE)\nul mkdir $(OUTPRE) - -midl : ccs_request.h ccs_reply.h - -$(OUTPRE)ccapiserver.exe: $(OBJS) - $(LINK) $(LFLAGS) /map:$*.map /out:$@ $(OBJS) $(LIBS) $(conlibsdll) $(conflags) - -finish : - @echo "Finished building ccapiserver.exe" - cd - -clean:: - if exist $(OUTPRE)*.exe del $(OUTPRE)*.exe - if exist $(OUTPRE)*.obj del $(OUTPRE)*.obj - if exist $(OUTPRE)*.res del $(OUTPRE)*.res - if exist $(OUTPRE)*.map del $(OUTPRE)*.map - if exist $(OUTPRE)*.pdb del $(OUTPRE)*.pdb - if exist *.err del *.err - if exist $(SRCTMP) rm -rf $(SRCTMP) +# makefile: Constructs the Kerberos for Windows CCAPI server. + +#BUILDTOP is krb5/src and is relative to krb5/src/ccapi/server/win, for making Makefile. +BUILDTOP=..\..\.. +CCAPI = $(BUILDTOP)\CCAPI +CO = $(CCAPI)\common +COWIN = $(CCAPI)\common\win +CCUTIL = $(CCAPI)\common\win\OldCC +SRVDIR = $(CCAPI)\server +SRVWIN = $(SRVDIR)\win +POSIX = $(BUILDTOP)\lib\krb5\posix +SRCTMP = $(SRVWIN)\srctmp + +!if defined(KRB5_KFW_COMPILE) +KFWINC= /I$(BUILDTOP)\..\..\krbcc\include +!endif + +OBJS = $(OUTPRE)cci_array_internal.$(OBJEXT) \ + $(OUTPRE)cci_cred_union.$(OBJEXT) \ + $(OUTPRE)cci_debugging.$(OBJEXT) \ + $(OUTPRE)cci_identifier.$(OBJEXT) \ + $(OUTPRE)cci_message.$(OBJEXT) \ + $(OUTPRE)cci_os_debugging.$(OBJEXT) \ + $(OUTPRE)cci_os_identifier.$(OBJEXT) \ + $(OUTPRE)ccs_array.$(OBJEXT) \ + $(OUTPRE)ccs_cache_collection.$(OBJEXT) \ + $(OUTPRE)ccs_callback.$(OBJEXT) \ + $(OUTPRE)ccs_ccache.$(OBJEXT) \ + $(OUTPRE)ccs_ccache_iterator.$(OBJEXT) \ + $(OUTPRE)ccs_client.$(OBJEXT) \ + $(OUTPRE)ccs_credentials.$(OBJEXT) \ + $(OUTPRE)ccs_credentials_iterator.$(OBJEXT) \ + $(OUTPRE)ccs_list.$(OBJEXT) \ + $(OUTPRE)ccs_list_internal.$(OBJEXT) \ + $(OUTPRE)ccs_lock.$(OBJEXT) \ + $(OUTPRE)ccs_lock_state.$(OBJEXT) \ + $(OUTPRE)ccs_os_pipe.$(OBJEXT) \ + $(OUTPRE)ccs_os_server.$(OBJEXT) \ + $(OUTPRE)ccs_pipe.$(OBJEXT) \ + $(OUTPRE)ccs_reply_c.$(OBJEXT) \ + $(OUTPRE)ccs_request_proc.$(OBJEXT) \ + $(OUTPRE)ccs_server.$(OBJEXT) \ + $(OUTPRE)ccs_win_pipe.$(OBJEXT) \ + $(OUTPRE)ccs_request_s.$(OBJEXT) \ + $(OUTPRE)ccutils.$(OBJEXT) \ + $(OUTPRE)init.$(OBJEXT) \ + $(OUTPRE)opts.$(OBJEXT) \ + $(OUTPRE)secure.$(OBJEXT) \ + $(OUTPRE)tls.$(OBJEXT) \ + $(OUTPRE)util.$(OBJEXT) \ + $(OUTPRE)win-utils.$(OBJEXT) \ + $(OUTPRE)WorkItem.$(OBJEXT) \ + $(OUTPRE)WorkQueue.$(OBJEXT) + +##### Options + +# Because all the sources are pulled together into the temp directory SRCTMP, +# the only includes we need are to directories outside of ccapi. +LOCALINCLUDES = /I..\$(BUILDTOP) /I..\$(BUILDTOP)\include /I..\$(BUILDTOP)\include\krb5 $(KFWINC) \ + -I..\$(BUILDTOP)\util\et /I. +MIDLI = /I..\$(BUILDTOP)\include + +CPPFLAGS = $(CPPFLAGS) /EHsc -D_CRTAPI1=_cdecl -D_CRTAPI2=_cdecl -DWINVER=0x0501 \ +-D_WIN32_WINNT=0x0501 -D_CRT_SECURE_NO_WARNINGS + +##### Linker +LINK = link +LIBS = ..\$(SLIB) rpcrt4.lib advapi32.lib ws2_32.lib user32.lib +LFLAGS = /nologo $(LOPTS) + + +all:: Makefile copysrc midl $(OUTPRE)ccapiserver.exe finish + +ccs_request.h ccs_request_c.c ccs_request_s.c : ccs_request.idl ccs_request.acf + midl $(MIDL_OPTIMIZATION) $(MIDLI) -oldnames -cpp_cmd $(CC) -cpp_opt "-E" \ + ccs_request.idl + +ccs_reply.h ccs_reply_c.c ccs_reply_s.c : ccs_reply.idl ccs_reply.acf + midl $(MIDL_OPTIMIZATION) $(MIDLI) -oldnames -cpp_cmd $(CC) -cpp_opt "-E" \ + ccs_reply.idl + +copysrc : + echo "Copying all sources needed to build ccapiserver.exe to $(SRCTMP)" + if NOT exist $(SRCTMP)\nul mkdir $(SRCTMP) + xcopy /D/Y $(CO)\*.* $(SRCTMP) + xcopy /D/Y $(COWIN)\*.* $(SRCTMP) + xcopy /D/Y $(CCUTIL)\*.* $(SRCTMP) + xcopy /D/Y $(SRVDIR)\*.* $(SRCTMP) + xcopy /D/Y $(SRVWIN)\*.* $(SRCTMP) + cd $(SRCTMP) + if NOT exist $(OUTPRE)\nul mkdir $(OUTPRE) + +midl : ccs_request.h ccs_reply.h + +$(OUTPRE)ccapiserver.exe: $(OBJS) + $(LINK) $(LFLAGS) /map:$*.map /out:$@ $(OBJS) $(LIBS) $(conlibsdll) $(conflags) + +finish : + @echo "Finished building ccapiserver.exe" + cd + +clean:: + if exist $(OUTPRE)*.exe del $(OUTPRE)*.exe + if exist $(OUTPRE)*.obj del $(OUTPRE)*.obj + if exist $(OUTPRE)*.res del $(OUTPRE)*.res + if exist $(OUTPRE)*.map del $(OUTPRE)*.map + if exist $(OUTPRE)*.pdb del $(OUTPRE)*.pdb + if exist *.err del *.err + if exist $(SRCTMP) rm -rf $(SRCTMP) diff --git a/src/ccapi/server/win/Server.sln b/src/ccapi/server/win/Server.sln index 64cc7f08c..ea1bd455f 100644 --- a/src/ccapi/server/win/Server.sln +++ b/src/ccapi/server/win/Server.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server", "Server.vcproj", "{114DCD80-6D13-4AAA-9510-B51CE6D94C1C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Debug|Win32.ActiveCfg = Debug|Win32 - {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Debug|Win32.Build.0 = Debug|Win32 - {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Release|Win32.ActiveCfg = Release|Win32 - {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server", "Server.vcproj", "{114DCD80-6D13-4AAA-9510-B51CE6D94C1C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Debug|Win32.ActiveCfg = Debug|Win32 + {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Debug|Win32.Build.0 = Debug|Win32 + {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Release|Win32.ActiveCfg = Release|Win32 + {114DCD80-6D13-4AAA-9510-B51CE6D94C1C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/ccapi/server/win/Server.vcproj b/src/ccapi/server/win/Server.vcproj index 39db361d8..626c7a3c7 100644 --- a/src/ccapi/server/win/Server.vcproj +++ b/src/ccapi/server/win/Server.vcproj @@ -1,227 +1,227 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ccapi/server/win/WorkItem.cpp b/src/ccapi/server/win/WorkItem.cpp index 1b1725a8a..22e209de9 100644 --- a/src/ccapi/server/win/WorkItem.cpp +++ b/src/ccapi/server/win/WorkItem.cpp @@ -1,126 +1,126 @@ -/* - * $Header$ - * - * Copyright 2008 Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -#include -#include "assert.h" - -#pragma warning (disable : 4996) - -#include "win-utils.h" -#include "WorkItem.h" - -extern "C" { -#include "cci_debugging.h" - } - -// CountedBuffer makes a copy of the data. Each CountedBuffer must be deleted. - -void deleteBuffer(char** buf) { - if (*buf) { - delete [](*buf); - *buf = NULL; - } - } - -// WorkItem contains a CountedBuffer which must be deleted, -// so each WorkItem must be deleted. -WorkItem::WorkItem(k5_ipc_stream buf, WIN_PIPE* pipe, const long type, const long sst) -: _buf(buf), _rpcmsg(type), _pipe(pipe), _sst(sst) { } - -WorkItem::WorkItem(const WorkItem& item) : _buf(NULL), _rpcmsg(0), _pipe(NULL), _sst(0) { - - k5_ipc_stream _buf = NULL; - krb5int_ipc_stream_new(&_buf); - krb5int_ipc_stream_write(_buf, - krb5int_ipc_stream_data(item.payload()), - krb5int_ipc_stream_size(item.payload()) ); - WorkItem(_buf, item._pipe, item._rpcmsg, item._sst); - } - -WorkItem::WorkItem() : _buf(NULL), _rpcmsg(CCMSG_INVALID), _pipe(NULL), _sst(0) { } - -WorkItem::~WorkItem() { - if (_buf) krb5int_ipc_stream_release(_buf); - if (_pipe) ccs_win_pipe_release(_pipe); - } - -const k5_ipc_stream WorkItem::take_payload() { - k5_ipc_stream temp = payload(); - _buf = NULL; - return temp; - } - -WIN_PIPE* WorkItem::take_pipe() { - WIN_PIPE* temp = pipe(); - _pipe = NULL; - return temp; - } - -WorkList::WorkList() { - assert(InitializeCriticalSectionAndSpinCount(&cs, 0x80000400)); - } - -WorkList::~WorkList() { - // Delete any WorkItems in the queue: - WorkItem* item; - cci_debug_printf("%s", __FUNCTION__); - char buf[2048]; - char* pbuf = (char*)buf; - while (remove(&item)) { - cci_debug_printf("WorkList::~WorkList() deleting %s", item->print(pbuf)); - delete item; - } - - DeleteCriticalSection(&cs); - } - -char* WorkItem::print(char* buf) { - sprintf(buf, "WorkItem msg#:%d sst:%ld pipe:<%s>/0x%X", _rpcmsg, _sst, - ccs_win_pipe_getUuid(_pipe), ccs_win_pipe_getHandle(_pipe)); - return buf; - } - -int WorkList::add(WorkItem* item) { - EnterCriticalSection(&cs); - wl.push_front(item); - LeaveCriticalSection(&cs); - return 1; - } - -int WorkList::remove(WorkItem** item) { - bool bEmpty; - - bEmpty = wl.empty() & 1; - - if (!bEmpty) { - EnterCriticalSection(&cs); - *item = wl.back(); - wl.pop_back(); - LeaveCriticalSection(&cs); - } - - return !bEmpty; - } +/* + * $Header$ + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#include +#include "assert.h" + +#pragma warning (disable : 4996) + +#include "win-utils.h" +#include "WorkItem.h" + +extern "C" { +#include "cci_debugging.h" + } + +// CountedBuffer makes a copy of the data. Each CountedBuffer must be deleted. + +void deleteBuffer(char** buf) { + if (*buf) { + delete [](*buf); + *buf = NULL; + } + } + +// WorkItem contains a CountedBuffer which must be deleted, +// so each WorkItem must be deleted. +WorkItem::WorkItem(k5_ipc_stream buf, WIN_PIPE* pipe, const long type, const long sst) +: _buf(buf), _rpcmsg(type), _pipe(pipe), _sst(sst) { } + +WorkItem::WorkItem(const WorkItem& item) : _buf(NULL), _rpcmsg(0), _pipe(NULL), _sst(0) { + + k5_ipc_stream _buf = NULL; + krb5int_ipc_stream_new(&_buf); + krb5int_ipc_stream_write(_buf, + krb5int_ipc_stream_data(item.payload()), + krb5int_ipc_stream_size(item.payload()) ); + WorkItem(_buf, item._pipe, item._rpcmsg, item._sst); + } + +WorkItem::WorkItem() : _buf(NULL), _rpcmsg(CCMSG_INVALID), _pipe(NULL), _sst(0) { } + +WorkItem::~WorkItem() { + if (_buf) krb5int_ipc_stream_release(_buf); + if (_pipe) ccs_win_pipe_release(_pipe); + } + +const k5_ipc_stream WorkItem::take_payload() { + k5_ipc_stream temp = payload(); + _buf = NULL; + return temp; + } + +WIN_PIPE* WorkItem::take_pipe() { + WIN_PIPE* temp = pipe(); + _pipe = NULL; + return temp; + } + +WorkList::WorkList() { + assert(InitializeCriticalSectionAndSpinCount(&cs, 0x80000400)); + } + +WorkList::~WorkList() { + // Delete any WorkItems in the queue: + WorkItem* item; + cci_debug_printf("%s", __FUNCTION__); + char buf[2048]; + char* pbuf = (char*)buf; + while (remove(&item)) { + cci_debug_printf("WorkList::~WorkList() deleting %s", item->print(pbuf)); + delete item; + } + + DeleteCriticalSection(&cs); + } + +char* WorkItem::print(char* buf) { + sprintf(buf, "WorkItem msg#:%d sst:%ld pipe:<%s>/0x%X", _rpcmsg, _sst, + ccs_win_pipe_getUuid(_pipe), ccs_win_pipe_getHandle(_pipe)); + return buf; + } + +int WorkList::add(WorkItem* item) { + EnterCriticalSection(&cs); + wl.push_front(item); + LeaveCriticalSection(&cs); + return 1; + } + +int WorkList::remove(WorkItem** item) { + bool bEmpty; + + bEmpty = wl.empty() & 1; + + if (!bEmpty) { + EnterCriticalSection(&cs); + *item = wl.back(); + wl.pop_back(); + LeaveCriticalSection(&cs); + } + + return !bEmpty; + } diff --git a/src/ccapi/server/win/WorkQueue.cpp b/src/ccapi/server/win/WorkQueue.cpp index f16ad117e..cc12054a1 100644 --- a/src/ccapi/server/win/WorkQueue.cpp +++ b/src/ccapi/server/win/WorkQueue.cpp @@ -1,61 +1,61 @@ -/* - * $Header$ - * - * Copyright 2008 Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -extern "C" { - #include "cci_debugging.h" - } - -#include "WorkItem.h" - -WorkList worklist; - -/* C interfaces: */ -EXTERN_C bool worklist_isEmpty() { - return worklist.isEmpty(); - } - -EXTERN_C int worklist_add( const long rpcmsg, - const ccs_pipe_t pipe, - const k5_ipc_stream stream, - const time_t serverStartTime) { - return worklist.add(new WorkItem(stream, pipe, rpcmsg, serverStartTime) ); - } - -EXTERN_C int worklist_remove(long* rpcmsg, - ccs_pipe_t* pipe, - k5_ipc_stream* stream, - time_t* sst) { - WorkItem* item = NULL; - cc_int32 err = worklist.remove(&item); - - *rpcmsg = item->type(); - *pipe = item->take_pipe(); - *stream = item->take_payload(); - *sst = item->sst(); - delete item; - return err; - } - +/* + * $Header$ + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +extern "C" { + #include "cci_debugging.h" + } + +#include "WorkItem.h" + +WorkList worklist; + +/* C interfaces: */ +EXTERN_C bool worklist_isEmpty() { + return worklist.isEmpty(); + } + +EXTERN_C int worklist_add( const long rpcmsg, + const ccs_pipe_t pipe, + const k5_ipc_stream stream, + const time_t serverStartTime) { + return worklist.add(new WorkItem(stream, pipe, rpcmsg, serverStartTime) ); + } + +EXTERN_C int worklist_remove(long* rpcmsg, + ccs_pipe_t* pipe, + k5_ipc_stream* stream, + time_t* sst) { + WorkItem* item = NULL; + cc_int32 err = worklist.remove(&item); + + *rpcmsg = item->type(); + *pipe = item->take_pipe(); + *stream = item->take_payload(); + *sst = item->sst(); + delete item; + return err; + } + diff --git a/src/ccapi/server/win/ccs_os_server.cpp b/src/ccapi/server/win/ccs_os_server.cpp index b22fdfa9b..e0695876d 100644 --- a/src/ccapi/server/win/ccs_os_server.cpp +++ b/src/ccapi/server/win/ccs_os_server.cpp @@ -1,963 +1,963 @@ -/* - * $Header$ - * - * Copyright 2008 Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -#include "process.h" -#include "windows.h" - -extern "C" { -#include "ccs_common.h" -#include "ccs_os_notify.h" -#include "ccs_os_server.h" -#include "ccs_reply.h" -#include "ccs_request.h" -#include "win-utils.h" -#include "ccutils.h" - } - -#include "WorkQueue.h" -#include "util.h" -#include "opts.hxx" -#include "init.hxx" - -#pragma warning (disable : 4996) - -BOOL bListen = TRUE; /* Why aren't bool and true defined? */ -const char* sessID = NULL; /* The logon session we are running on behalf of. */ -time_t _sst = 0; -unsigned char* pszNetworkAddress = NULL; -unsigned char* pszStringBinding = NULL; -BOOL bRpcHandleInited = FALSE; -_RPC_ASYNC_STATE* rpcState = NULL; - -/* Thread procedures can take only one void* argument. We put all the args we want - to pass into this struct and then pass a pointer to the struct: */ -struct RpcRcvArgs { - char* networkAddress; - unsigned char* protocolSequence; - unsigned char* sessID; /* Used for this server's endpoint */ - unsigned char* uuid; /* Used for client's UUID */ - ParseOpts::Opts* opts; - RPC_STATUS status; - } rpcargs = { NULL, /* pszNetworkAddress */ - (unsigned char*)"ncalrpc", /* pszProtocolSequence */ - NULL, /* sessID placeholder */ - NULL, /* uuid placeholder */ - NULL }; /* Opts placeholder */ - -/* Command line format: - argv[0] Program name - argv[1] session ID to use - argv[2] "D" Debug: go into infinite loop in ccs_os_server_initialize so process - can be attached in debugger. - Any other value: continue - */ -#define N_FIXED_ARGS 3 -#define SERVER_REPLY_RPC_HANDLE ccs_reply_IfHandle - -/* Forward declarations: */ -void receiveLoop(void* rpcargs); -void connectionListener(void* rpcargs); -void Usage(const char* argv0); -void printError(TCHAR* msg); -void setMySST() {_sst = time(&_sst);} -time_t getMySST() {return _sst;} -RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe); -void RPC_ENTRY clientListener( _RPC_ASYNC_STATE*, - void* Context, - RPC_ASYNC_EVENT Event); -RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface, - IN void *Context); -RPC_STATUS send_init(char* clientUUID); -//DWORD alloc_name(LPSTR* pname, LPSTR postfix); - - -/* The layout of the rest of this module: - - The four entrypoints defined in ccs_os_server.h: - ccs_os_server_initialize - cc_int32 ccs_os_server_cleanup - cc_int32 ccs_os_server_listen_loop - cc_int32 ccs_os_server_send_reply - - Other routines needed by those four. - */ - -/* ------------------------------------------------------------------------ */ - -cc_int32 ccs_os_server_initialize (int argc, const char *argv[]) { - cc_int32 err = 0; - ParseOpts::Opts opts = { 0 }; - ParseOpts PO; - BOOL bAdjustedShutdown = FALSE; - HMODULE hKernel32 = GetModuleHandle("kernel32"); - - if (!err) { - sessID = argv[1]; - setMySST(); - - opts.cMinCalls = 1; - opts.cMaxCalls = 20; - opts.fDontWait = TRUE; - -#ifdef CCAPI_TEST_OPTIONS - PO.SetValidOpts("kemnfubc"); -#else - PO.SetValidOpts("kc"); -#endif - - PO.Parse(opts, argc, (char**)argv); - -// while(*argv[2] == 'D') {} /* Hang here to attach process with debugger. */ - - if (hKernel32) { - typedef BOOL (WINAPI *FP_SetProcessShutdownParameters)(DWORD, DWORD); - FP_SetProcessShutdownParameters pSetProcessShutdownParameters = - (FP_SetProcessShutdownParameters) - GetProcAddress(hKernel32, "SetProcessShutdownParameters"); - if (pSetProcessShutdownParameters) { - bAdjustedShutdown = pSetProcessShutdownParameters(100, 0); - } - } - cci_debug_printf("%s Shutdown Parameters", - bAdjustedShutdown ? "Adjusted" : "Did not adjust"); - - err = Init::Initialize(); - } - -// if (!err) { -// if (opts.bShutdown) { -// status = shutdown_server(opts.pszEndpoint); -// } -// } -// else { -// status = startup_server(opts); -// } - - if (err) { - Init::Cleanup(); - fprintf( stderr, "An error occured while %s the server (%u)\n", - opts.bShutdown ? "shutting down" : "starting/running", - err); - exit(cci_check_error (err)); - } - - return cci_check_error (err); - } - -/* ------------------------------------------------------------------------ */ - -cc_int32 ccs_os_server_cleanup (int argc, const char *argv[]) { - cc_int32 err = 0; - - cci_debug_printf("%s for user <%s> shutting down.", argv[0], argv[1]); - - return cci_check_error (err); - } - -/* ------------------------------------------------------------------------ */ - -/* This function takes work items off the work queue and executes them. - * This is the one and only place where the multi-threaded Windows code - * calls into the single-threaded common code. - * - * The actual 'listening' for requests from clients happens after receiveloop - * establishes the RPC endpoint the clients will connect to and the RPC procedures - * put the work items into the work queue. - */ -cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[]) { - cc_int32 err = 0; - uintptr_t threadStatus; - unsigned int loopCounter = 0; - - ParseOpts::Opts opts = { 0 }; - ParseOpts PO; - - opts.cMinCalls = 1; - opts.cMaxCalls = 20; - opts.fDontWait = TRUE; - -#ifdef CCAPI_TEST_OPTIONS - PO.SetValidOpts("kemnfubc"); -#else - PO.SetValidOpts("kc"); -#endif - PO.Parse(opts, argc, (char**)argv); - - - //++ debug stuff - #define INFO_BUFFER_SIZE 32767 - TCHAR infoBuf[INFO_BUFFER_SIZE]; - DWORD bufCharCount = INFO_BUFFER_SIZE; - // Get and display the user name. - bufCharCount = INFO_BUFFER_SIZE; - if( !GetUserName( infoBuf, &bufCharCount ) ) printError( TEXT("GetUserName") ); - //-- - - /* Sending the reply from within the request RPC handler doesn't seem to work. - So we listen for requests in a separate thread and put the requests in a - queue. */ - rpcargs.sessID = (unsigned char*)sessID; - rpcargs.opts = &opts; - threadStatus = _beginthread(receiveLoop, 0, (void*)&rpcargs); - - /* We handle the queue entries here. Work loop: */ - while (TRUE) { - loopCounter++; - if (worklist_isEmpty() & 1) { - SleepEx(1000, TRUE); - } - else if (TRUE) { // Take next WorkItem from the queue: - k5_ipc_stream buf = NULL; - long rpcmsg = CCMSG_INVALID; - time_t serverStartTime = 0xDEADDEAD; - RPC_STATUS status = 0; - char* uuid = NULL; - k5_ipc_stream stream = NULL; - ccs_pipe_t pipe = NULL; - ccs_pipe_t pipe2 = NULL; - - if (worklist_remove(&rpcmsg, &pipe, &buf, &serverStartTime)) { - uuid = ccs_win_pipe_getUuid(pipe); -#if 0 - cci_debug_printf("%s: processing WorkItem msg:%ld pipeUUID:<%s> pipeHandle:0x%X SST:%ld", - __FUNCTION__, rpcmsg, uuid, ccs_win_pipe_getHandle(pipe), serverStartTime); -#endif - if (serverStartTime <= getMySST()) { - switch (rpcmsg) { - case CCMSG_CONNECT: { - cci_debug_printf(" Processing CONNECT"); - rpcargs.uuid = (unsigned char*)uuid; - - // Even if a disconnect message is received before this code finishes, - // it won't be dequeued and processed until after this code finishes. - // So we can add the client after starting the connection listener. - connectionListener((void*)&rpcargs); - status = rpcargs.status; - - if (!status) { - status = ccs_server_add_client(pipe); - } - if (!status) {status = send_connection_reply(pipe);} - break; - } - case CCMSG_DISCONNECT: { - cci_debug_printf(" Processing DISCONNECT"); - if (!status) { - status = ccs_server_remove_client(pipe); - } - break; - } - case CCMSG_REQUEST: - cci_debug_printf(" Processing REQUEST"); - ccs_pipe_copy(&pipe2, pipe); - // Dispatch message here, setting both pipes to the client UUID: - err = ccs_server_handle_request (pipe, pipe2, buf); - break; - case CCMSG_PING: - cci_debug_printf(" Processing PING"); - err = krb5int_ipc_stream_new (&stream); - err = krb5int_ipc_stream_write(stream, "This is a test of the emergency broadcasting system", 52); - err = ccs_os_server_send_reply(pipe, stream); - break; - default: - cci_debug_printf("Huh? Received invalid message type %ld from UUID:<%s>", - rpcmsg, uuid); - break; - } - if (buf) krb5int_ipc_stream_release(buf); - /* Don't free uuid, which was allocated here. A pointer to it is in the - rpcargs struct which was passed to connectionListener which will be - received by ccapi_listen when the client exits. ccapi_listen needs - the uuid to know which client to disconnect. - */ - } - // Server's start time is different from what the client thinks. - // That means the server has rebooted since the client connected. - else { - cci_debug_printf("Whoops! Server has rebooted since client established connection."); - } - } - else {cci_debug_printf("Huh? Queue not empty but no item to remove.");} - } - } - - return cci_check_error (err); - } - -/* ------------------------------------------------------------------------ */ - -cc_int32 ccs_os_server_send_reply (ccs_pipe_t in_pipe, - k5_ipc_stream in_reply_stream) { - - /* ccs_pipe_t in_reply_pipe is a char* reply endpoint. - k5_ipc_stream in_reply_stream is the data to be sent. - */ - - cc_int32 err = 0; - char* uuid = ccs_win_pipe_getUuid(in_pipe); - HANDLE h = ccs_win_pipe_getHandle(in_pipe); - - if (!err) { - err = send_init(uuid); // Sets RPC handle to be used. - } - - if (!err) { - RpcTryExcept { - long status; - ccs_rpc_request_reply( // make call with user message - CCMSG_REQUEST_REPLY, /* Message type */ - (unsigned char*)&h, /* client's tspdata* */ - (unsigned char*)uuid, - getMySST(), - krb5int_ipc_stream_size(in_reply_stream), /* Length of buffer */ - (const unsigned char*)krb5int_ipc_stream_data(in_reply_stream), /* Data buffer */ - &status ); /* Return code */ - } - RpcExcept(1) { - cci_check_error(RpcExceptionCode()); - } - RpcEndExcept - } - - /* The calls to the remote procedures are complete. */ - /* Free whatever we allocated: */ - err = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); - - return cci_check_error (err); - } - - -/* Windows-specific routines: */ - -void Usage(const char* argv0) { - printf("Usage:\n"); - printf("%s [m maxcalls] [n mincalls] [f dontwait] [h|?]]\n", argv0); - printf(" CCAPI server process.\n"); - printf(" h|? whow usage message. <\n"); - } - -/* ------------------------------------------------------------------------ */ -/* The receive thread repeatedly issues RpcServerListen. - When a message arrives, it is handled in the RPC procedure. - */ -void receiveLoop(void* rpcargs) { - - struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs; - RPC_STATUS status = FALSE; - unsigned char* pszSecurity = NULL; - LPSTR endpoint = NULL; - LPSTR event_name = NULL; - PSECURITY_DESCRIPTOR psd = NULL; - HANDLE hEvent = 0; - Init::InitInfo info; - - cci_debug_printf("THREAD BEGIN: %s", __FUNCTION__); - - status = Init::Info(info); - - /* Build complete RPC endpoint using previous CCAPI implementation: */ - if (!status) { - if (!rcvargs->opts->pszEndpoint) { - if (!status) { - status = alloc_name(&endpoint, "ep", isNT()); - } - - if (!status) { - status = alloc_name(&event_name, "startup", isNT()); - } - - if (!status) { - hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name); - // We ignore any error opening the event because we do not know who started us. - // [Comment paraphrased from previous implementation, whence it was copied.] - } - } - else { - endpoint = rcvargs->opts->pszEndpoint; - } - } - - cci_debug_printf("%s Registering endpoint %s", __FUNCTION__, endpoint); - - if (!status && isNT()) { - status = alloc_own_security_descriptor_NT(&psd); - } - - if (!status) { - status = RpcServerUseProtseqEp(rcvargs->protocolSequence, - rcvargs->opts->cMaxCalls, - (RPC_CSTR)endpoint, - rcvargs->opts->bDontProtect ? 0 : psd); // SD - } - - if (!status) { - status = RpcServerRegisterAuthInfo(0, // server principal - RPC_C_AUTHN_WINNT, - 0, - 0); - } - - while (bListen && !status) { - cci_debug_printf("%s is listening ...", __FUNCTION__); - - if (!info.isNT) { - status = RpcServerRegisterIf(ccs_request_ServerIfHandle, // interface - NULL, // MgrTypeUuid - NULL); // MgrEpv; null means use default - } - else { - status = info.fRpcServerRegisterIfEx(ccs_request_ServerIfHandle, // interface - NULL, // MgrTypeUuid - NULL, // MgrEpv; 0 means default - RPC_IF_ALLOW_SECURE_ONLY, - rcvargs->opts->cMaxCalls, - rcvargs->opts->bSecCallback ? - (RPC_IF_CALLBACK_FN*)sec_callback : 0 ); - } - - if (!status) { - status = RpcServerListen(rcvargs->opts->cMinCalls, - rcvargs->opts->cMaxCalls, - rcvargs->opts->fDontWait); - } - - if (!status) { - if (rcvargs->opts->fDontWait) { - if (hEvent) SetEvent(hEvent); // Ignore any error -- SetEvent is an optimization. - status = RpcMgmtWaitServerListen(); - } - } - } - - if (status) { // Cleanup in case of errors: - if (hEvent) CloseHandle(hEvent); - free_alloc_p(&event_name); - free_alloc_p(&psd); - if (endpoint && (endpoint != rcvargs->opts->pszEndpoint)) - free_alloc_p(&endpoint); - } - - _endthread(); - } // End receiveLoop - - -#if 0 - - return status; -} -#endif - - - -/* ------------------------------------------------------------------------ */ -/* The connection listener thread waits forever for a call to the CCAPI_CLIENT_ - endpoint, ccapi_listen function to complete. If the call completes or gets an - RPC exception, it means the client has disappeared. - - A separate connectionListener is started for each client that has connected to the server. - */ - -void connectionListener(void* rpcargs) { - - struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs; - RPC_STATUS status = FALSE; - char* endpoint; - unsigned char* pszOptions = NULL; - unsigned char * pszUuid = NULL; - - endpoint = clientEndpoint((char*)rcvargs->uuid); - rpcState = (RPC_ASYNC_STATE*)malloc(sizeof(RPC_ASYNC_STATE)); - status = RpcAsyncInitializeHandle(rpcState, sizeof(RPC_ASYNC_STATE)); - cci_debug_printf(""); - cci_debug_printf("%s About to LISTEN to <%s>", __FUNCTION__, endpoint); - - rpcState->UserInfo = rcvargs->uuid; - rpcState->NotificationType = RpcNotificationTypeApc; - rpcState->u.APC.NotificationRoutine = clientListener; - rpcState->u.APC.hThread = 0; - - /* [If in use] Free previous binding: */ - if (bRpcHandleInited) { - // Free previous binding (could have been used to call ccapi_listen - // in a different client thread). - // Don't check result or update status. - RpcStringFree(&pszStringBinding); - RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); - bRpcHandleInited = FALSE; - } - - /* Set up binding to the client's endpoint: */ - if (!status) { - status = RpcStringBindingCompose( - pszUuid, - pszProtocolSequence, - pszNetworkAddress, - (RPC_CSTR)endpoint, - pszOptions, - &pszStringBinding); - } - - /* Set the binding handle that will be used to bind to the server. */ - if (!status) { - status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE); - } - if (!status) {bRpcHandleInited = TRUE;} - - RpcTryExcept { - cci_debug_printf(" Calling remote procedure ccapi_listen"); - ccapi_listen(rpcState, SERVER_REPLY_RPC_HANDLE, CCMSG_LISTEN, &status); - /* Asynchronous call will return immediately. */ - } - RpcExcept(1) { - status = cci_check_error(RpcExceptionCode()); - } - RpcEndExcept - - rcvargs->status = status; - } // End connectionListener - - -void RPC_ENTRY clientListener( - _RPC_ASYNC_STATE* pAsync, - void* Context, - RPC_ASYNC_EVENT Event - ) { - - ccs_pipe_t pipe = ccs_win_pipe_new((char*)pAsync->UserInfo, NULL); - - cci_debug_printf("%s(0x%X, ...) async routine for <0x%X:%s>!", - __FUNCTION__, pAsync, pAsync->UserInfo, pAsync->UserInfo); - - worklist_add( CCMSG_DISCONNECT, - pipe, - NULL, /* No payload with connect request */ - (const time_t)0 ); /* No server session number with connect request */ - } - - -void printError( TCHAR* msg ) { - DWORD eNum; - TCHAR sysMsg[256]; - TCHAR* p; - - eNum = GetLastError( ); - FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, eNum, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - sysMsg, 256, NULL ); - - // Trim the end of the line and terminate it with a null - p = sysMsg; - while( ( *p > 31 ) || ( *p == 9 ) ) - ++p; - do { *p-- = 0; } while( ( p >= sysMsg ) && - ( ( *p == '.' ) || ( *p < 33 ) ) ); - - // Display the message - cci_debug_printf("%s failed with error %d (%s)", msg, eNum, sysMsg); - } - - -RPC_STATUS send_init(char* clientUUID) { - RPC_STATUS status; - unsigned char * pszUuid = NULL; - unsigned char * pszOptions = NULL; - - /* Use a convenience function to concatenate the elements of */ - /* the string binding into the proper sequence. */ - status = RpcStringBindingCompose(pszUuid, - pszProtocolSequence, - pszNetworkAddress, - (unsigned char*)clientEndpoint(clientUUID), - pszOptions, - &pszStringBinding); - if (status) {return (status);} - - /* Set the binding handle that will be used to bind to the RPC server [the 'client']. */ - status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE); - return (status); - } - -RPC_STATUS send_finish() { - RPC_STATUS status; - /* Can't shut down client -- it runs listen function which */ - /* server uses to detect the client going away. */ - - /* The calls to the remote procedures are complete. */ - /* Free the string and the binding handle */ - status = RpcStringFree(&pszStringBinding); // remote calls done; unbind - if (status) {return (status);} - - status = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); // remote calls done; unbind - - return (status); - } - -RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe) { - char* uuid = ccs_win_pipe_getUuid (in_pipe); - HANDLE h = ccs_win_pipe_getHandle(in_pipe); - RPC_STATUS status = send_init(uuid); - - RpcTryExcept { - ccs_rpc_connect_reply( // make call with user message - CCMSG_CONNECT_REPLY, /* Message type */ - (unsigned char*)&h, /* client's tspdata* */ - (unsigned char*)uuid, - getMySST(), /* Server's session number = it's start time */ - &status ); /* Return code */ - } - RpcExcept(1) { - cci_check_error(RpcExceptionCode()); - } - RpcEndExcept - - status = send_finish(); - return (status); - } - -#if 0 -DWORD alloc_name(LPSTR* pname, LPSTR postfix) { - DWORD len = strlen(sessID) + 1 + strlen(postfix) + 1; - - *pname = (LPSTR)malloc(len); - if (!*pname) return GetLastError(); - _snprintf(*pname, len, "%s.%s", sessID, postfix); - return 0; - } -#endif - -RPC_STATUS GetPeerName( RPC_BINDING_HANDLE hClient, - LPTSTR pszClientName, - int iMaxLen) { - RPC_STATUS Status = RPC_S_OK; - RPC_BINDING_HANDLE hServer = NULL; - PTBYTE pszStringBinding = NULL; - PTBYTE pszClientNetAddr = NULL; - PTBYTE pszProtSequence = NULL; - - memset(pszClientName, 0, iMaxLen * sizeof(TCHAR)); - - __try { - // Create a partially bound server handle from the client handle. - Status = RpcBindingServerFromClient (hClient, &hServer); - if (Status != RPC_S_OK) __leave; - - // Get the partially bound server string binding and parse it. - Status = RpcBindingToStringBinding (hServer, - &pszStringBinding); - if (Status != RPC_S_OK) __leave; - - // String binding only contains protocol sequence and client - // address, and is not currently implemented for named pipes. - Status = RpcStringBindingParse (pszStringBinding, NULL, - &pszProtSequence, &pszClientNetAddr, - NULL, NULL); - if (Status != RPC_S_OK) - __leave; - int iLen = lstrlen(pszClientName) + 1; - if (iMaxLen < iLen) - Status = RPC_S_BUFFER_TOO_SMALL; - lstrcpyn(pszClientName, (LPCTSTR)pszClientNetAddr, iMaxLen); - } - __finally { - if (pszProtSequence) - RpcStringFree (&pszProtSequence); - - if (pszClientNetAddr) - RpcStringFree (&pszClientNetAddr); - - if (pszStringBinding) - RpcStringFree (&pszStringBinding); - - if (hServer) - RpcBindingFree (&hServer); - } - return Status; -} - -struct client_auth_info { - RPC_AUTHZ_HANDLE authz_handle; - unsigned char* server_principal; // need to RpcFreeString this - ULONG authn_level; - ULONG authn_svc; - ULONG authz_svc; -}; - -RPC_STATUS -GetClientId( - RPC_BINDING_HANDLE hClient, - char* client_id, - int max_len, - client_auth_info* info - ) -{ - RPC_AUTHZ_HANDLE authz_handle = 0; - unsigned char* server_principal = 0; - ULONG authn_level = 0; - ULONG authn_svc = 0; - ULONG authz_svc = 0; - RPC_STATUS status = 0; - - memset(client_id, 0, max_len); - - if (info) { - memset(info, 0, sizeof(client_auth_info)); - } - - status = RpcBindingInqAuthClient(hClient, &authz_handle, - info ? &server_principal : 0, - &authn_level, &authn_svc, &authz_svc); - if (status == RPC_S_OK) - { - if (info) { - info->server_principal = server_principal; - info->authz_handle = authz_handle; - info->authn_level = authn_level; - info->authn_svc = authn_svc; - info->authz_svc = authz_svc; - } - - if (authn_svc == RPC_C_AUTHN_WINNT) { - WCHAR* username = (WCHAR*)authz_handle; - int len = lstrlenW(username) + 1; - if (max_len < len) - status = RPC_S_BUFFER_TOO_SMALL; - _snprintf(client_id, max_len, "%S", username); - } else { - status = RPC_S_UNKNOWN_AUTHN_SERVICE; - } - } - return status; -} - -char* -rpc_error_to_string( - RPC_STATUS status - ) -{ - switch(status) { - case RPC_S_OK: - return "OK"; - case RPC_S_INVALID_BINDING: - return "Invalid binding"; - case RPC_S_WRONG_KIND_OF_BINDING: - return "Wrong binding"; - case RPC_S_BINDING_HAS_NO_AUTH: - RpcRaiseException(RPC_S_BINDING_HAS_NO_AUTH); - return "Binding has no auth"; - default: - return "BUG: I am confused"; - } -} - -void -print_client_info( - RPC_STATUS peer_status, - const char* peer_name, - RPC_STATUS client_status, - const char* client_id, - client_auth_info* info - ) -{ - if (peer_status == RPC_S_OK || peer_status == RPC_S_BUFFER_TOO_SMALL) { - cci_debug_printf("%s Peer Name is \"%s\"", __FUNCTION__, peer_name); - } else { - cci_debug_printf("%s Error %u getting Peer Name (%s)", - __FUNCTION__, peer_status, rpc_error_to_string(peer_status)); - } - - if (client_status == RPC_S_OK || client_status == RPC_S_BUFFER_TOO_SMALL) { - if (info) { - cci_debug_printf("%s Client Auth Info" - "\tServer Principal: %s\n" - "\tAuthentication Level: %d\n" - "\tAuthentication Service: %d\n" - "\tAuthorization Service: %d\n", - __FUNCTION__, - info->server_principal, - info->authn_level, - info->authn_svc, - info->authz_svc); - } - cci_debug_printf("%s Client ID is \"%s\"", __FUNCTION__, client_id); - } else { - cci_debug_printf("%s Error getting Client Info (%u = %s)", - __FUNCTION__, client_status, rpc_error_to_string(client_status)); - } -} - -DWORD sid_check() { - DWORD status = 0; - HANDLE hToken_c = 0; - HANDLE hToken_s = 0; - PTOKEN_USER ptu_c = 0; - PTOKEN_USER ptu_s = 0; - DWORD len = 0; - BOOL bImpersonate = FALSE; - - // Note GetUserName will fail while impersonating at identify - // level. The workaround is to impersonate, OpenThreadToken, - // revert, call GetTokenInformation, and finally, call - // LookupAccountSid. - - // XXX - Note: This workaround does not appear to work. - // OpenThreadToken fails with error 1346: "Either a requid - // impersonation level was not provided or the provided - // impersonation level is invalid". - - status = RpcImpersonateClient(0); - - if (!status) { - bImpersonate = TRUE; - if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken_c)) - status = GetLastError(); - } - - if (!status) { - status = RpcRevertToSelf(); - } - - if (!status) { - bImpersonate = FALSE; - - len = 0; - GetTokenInformation(hToken_c, TokenUser, ptu_c, 0, &len); - if (len == 0) status = 1; - } - - if (!status) { - if (!(ptu_c = (PTOKEN_USER)LocalAlloc(0, len))) - status = GetLastError(); - } - - if (!status) { - if (!GetTokenInformation(hToken_c, TokenUser, ptu_c, len, &len)) - status = GetLastError(); - } - - if (!status) { - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken_s)) - status = GetLastError(); - } - - if (!status) { - len = 0; - GetTokenInformation(hToken_s, TokenUser, ptu_s, 0, &len); - if (len == 0) status = GetLastError(); - } - - if (!status) { - if (!(ptu_s = (PTOKEN_USER)LocalAlloc(0, len))) - status = GetLastError(); - } - - if (!status) { - if (!GetTokenInformation(hToken_s, TokenUser, ptu_s, len, &len)) - status = GetLastError(); - } - - if (!EqualSid(ptu_s->User.Sid, ptu_c->User.Sid)) - status = RPC_S_ACCESS_DENIED; - -/* Cleanup: */ - if (!hToken_c && !bImpersonate) - cci_debug_printf("%s Cannot impersonate (%u)", __FUNCTION__, status); - else if (!hToken_c) - cci_debug_printf("%s Failed to open client token (%u)", __FUNCTION__, status); - else if (bImpersonate) - cci_debug_printf("%s Failed to revert (%u)", __FUNCTION__, status); - else if (!ptu_c) - cci_debug_printf("%s Failed to get client token user info (%u)", - __FUNCTION__, status); - else if (!hToken_s) - cci_debug_printf("%s Failed to open server token (%u)", __FUNCTION__, status); - else if (!ptu_s) - cci_debug_printf("%s Failed to get server token user info (%u)", - __FUNCTION__, status); - else if (status == RPC_S_ACCESS_DENIED) - cci_debug_printf("%s SID **does not** match!", __FUNCTION__); - else if (status == RPC_S_OK) - cci_debug_printf("%s SID matches!", __FUNCTION__); - else - if (status) { - cci_debug_printf("%s unrecognized error %u", __FUNCTION__, status); - abort(); - } - - if (bImpersonate) RpcRevertToSelf(); - if (hToken_c && hToken_c != INVALID_HANDLE_VALUE) - CloseHandle(hToken_c); - if (ptu_c) LocalFree(ptu_c); - if (hToken_s && hToken_s != INVALID_HANDLE_VALUE) - CloseHandle(hToken_s); - if (ptu_s) LocalFree(ptu_s); - if (status) cci_debug_printf("%s returning %u", __FUNCTION__, status); - return status; - } - -RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface, - IN void *Context) { - char peer_name[1024]; - char client_name[1024]; - RPC_STATUS peer_status; - RPC_STATUS client_status; - - cci_debug_printf("%s", __FUNCTION__); - peer_status = GetPeerName(Context, peer_name, sizeof(peer_name)); - client_status = GetClientId(Context, client_name, sizeof(client_name), 0); - print_client_info(peer_status, peer_name, client_status, client_name, 0); - DWORD sid_status = sid_check(); - cci_debug_printf("%s returning (%u)", __FUNCTION__, sid_status); - return sid_status; - } - - - -/*********************************************************************/ -/* MIDL allocate and free */ -/*********************************************************************/ - -extern "C" void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) { - return(malloc(len)); - } - -extern "C" void __RPC_USER midl_user_free(void __RPC_FAR * ptr) { - free(ptr); - } - -/* stubs */ -extern "C" cc_int32 -ccs_os_notify_cache_collection_changed (ccs_cache_collection_t cc) -{ - return 0; -} - -extern "C" cc_int32 -ccs_os_notify_ccache_changed (ccs_cache_collection_t cc, const char *name) -{ - return 0; -} +/* + * $Header$ + * + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#include "process.h" +#include "windows.h" + +extern "C" { +#include "ccs_common.h" +#include "ccs_os_notify.h" +#include "ccs_os_server.h" +#include "ccs_reply.h" +#include "ccs_request.h" +#include "win-utils.h" +#include "ccutils.h" + } + +#include "WorkQueue.h" +#include "util.h" +#include "opts.hxx" +#include "init.hxx" + +#pragma warning (disable : 4996) + +BOOL bListen = TRUE; /* Why aren't bool and true defined? */ +const char* sessID = NULL; /* The logon session we are running on behalf of. */ +time_t _sst = 0; +unsigned char* pszNetworkAddress = NULL; +unsigned char* pszStringBinding = NULL; +BOOL bRpcHandleInited = FALSE; +_RPC_ASYNC_STATE* rpcState = NULL; + +/* Thread procedures can take only one void* argument. We put all the args we want + to pass into this struct and then pass a pointer to the struct: */ +struct RpcRcvArgs { + char* networkAddress; + unsigned char* protocolSequence; + unsigned char* sessID; /* Used for this server's endpoint */ + unsigned char* uuid; /* Used for client's UUID */ + ParseOpts::Opts* opts; + RPC_STATUS status; + } rpcargs = { NULL, /* pszNetworkAddress */ + (unsigned char*)"ncalrpc", /* pszProtocolSequence */ + NULL, /* sessID placeholder */ + NULL, /* uuid placeholder */ + NULL }; /* Opts placeholder */ + +/* Command line format: + argv[0] Program name + argv[1] session ID to use + argv[2] "D" Debug: go into infinite loop in ccs_os_server_initialize so process + can be attached in debugger. + Any other value: continue + */ +#define N_FIXED_ARGS 3 +#define SERVER_REPLY_RPC_HANDLE ccs_reply_IfHandle + +/* Forward declarations: */ +void receiveLoop(void* rpcargs); +void connectionListener(void* rpcargs); +void Usage(const char* argv0); +void printError(TCHAR* msg); +void setMySST() {_sst = time(&_sst);} +time_t getMySST() {return _sst;} +RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe); +void RPC_ENTRY clientListener( _RPC_ASYNC_STATE*, + void* Context, + RPC_ASYNC_EVENT Event); +RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface, + IN void *Context); +RPC_STATUS send_init(char* clientUUID); +//DWORD alloc_name(LPSTR* pname, LPSTR postfix); + + +/* The layout of the rest of this module: + + The four entrypoints defined in ccs_os_server.h: + ccs_os_server_initialize + cc_int32 ccs_os_server_cleanup + cc_int32 ccs_os_server_listen_loop + cc_int32 ccs_os_server_send_reply + + Other routines needed by those four. + */ + +/* ------------------------------------------------------------------------ */ + +cc_int32 ccs_os_server_initialize (int argc, const char *argv[]) { + cc_int32 err = 0; + ParseOpts::Opts opts = { 0 }; + ParseOpts PO; + BOOL bAdjustedShutdown = FALSE; + HMODULE hKernel32 = GetModuleHandle("kernel32"); + + if (!err) { + sessID = argv[1]; + setMySST(); + + opts.cMinCalls = 1; + opts.cMaxCalls = 20; + opts.fDontWait = TRUE; + +#ifdef CCAPI_TEST_OPTIONS + PO.SetValidOpts("kemnfubc"); +#else + PO.SetValidOpts("kc"); +#endif + + PO.Parse(opts, argc, (char**)argv); + +// while(*argv[2] == 'D') {} /* Hang here to attach process with debugger. */ + + if (hKernel32) { + typedef BOOL (WINAPI *FP_SetProcessShutdownParameters)(DWORD, DWORD); + FP_SetProcessShutdownParameters pSetProcessShutdownParameters = + (FP_SetProcessShutdownParameters) + GetProcAddress(hKernel32, "SetProcessShutdownParameters"); + if (pSetProcessShutdownParameters) { + bAdjustedShutdown = pSetProcessShutdownParameters(100, 0); + } + } + cci_debug_printf("%s Shutdown Parameters", + bAdjustedShutdown ? "Adjusted" : "Did not adjust"); + + err = Init::Initialize(); + } + +// if (!err) { +// if (opts.bShutdown) { +// status = shutdown_server(opts.pszEndpoint); +// } +// } +// else { +// status = startup_server(opts); +// } + + if (err) { + Init::Cleanup(); + fprintf( stderr, "An error occured while %s the server (%u)\n", + opts.bShutdown ? "shutting down" : "starting/running", + err); + exit(cci_check_error (err)); + } + + return cci_check_error (err); + } + +/* ------------------------------------------------------------------------ */ + +cc_int32 ccs_os_server_cleanup (int argc, const char *argv[]) { + cc_int32 err = 0; + + cci_debug_printf("%s for user <%s> shutting down.", argv[0], argv[1]); + + return cci_check_error (err); + } + +/* ------------------------------------------------------------------------ */ + +/* This function takes work items off the work queue and executes them. + * This is the one and only place where the multi-threaded Windows code + * calls into the single-threaded common code. + * + * The actual 'listening' for requests from clients happens after receiveloop + * establishes the RPC endpoint the clients will connect to and the RPC procedures + * put the work items into the work queue. + */ +cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[]) { + cc_int32 err = 0; + uintptr_t threadStatus; + unsigned int loopCounter = 0; + + ParseOpts::Opts opts = { 0 }; + ParseOpts PO; + + opts.cMinCalls = 1; + opts.cMaxCalls = 20; + opts.fDontWait = TRUE; + +#ifdef CCAPI_TEST_OPTIONS + PO.SetValidOpts("kemnfubc"); +#else + PO.SetValidOpts("kc"); +#endif + PO.Parse(opts, argc, (char**)argv); + + + //++ debug stuff + #define INFO_BUFFER_SIZE 32767 + TCHAR infoBuf[INFO_BUFFER_SIZE]; + DWORD bufCharCount = INFO_BUFFER_SIZE; + // Get and display the user name. + bufCharCount = INFO_BUFFER_SIZE; + if( !GetUserName( infoBuf, &bufCharCount ) ) printError( TEXT("GetUserName") ); + //-- + + /* Sending the reply from within the request RPC handler doesn't seem to work. + So we listen for requests in a separate thread and put the requests in a + queue. */ + rpcargs.sessID = (unsigned char*)sessID; + rpcargs.opts = &opts; + threadStatus = _beginthread(receiveLoop, 0, (void*)&rpcargs); + + /* We handle the queue entries here. Work loop: */ + while (TRUE) { + loopCounter++; + if (worklist_isEmpty() & 1) { + SleepEx(1000, TRUE); + } + else if (TRUE) { // Take next WorkItem from the queue: + k5_ipc_stream buf = NULL; + long rpcmsg = CCMSG_INVALID; + time_t serverStartTime = 0xDEADDEAD; + RPC_STATUS status = 0; + char* uuid = NULL; + k5_ipc_stream stream = NULL; + ccs_pipe_t pipe = NULL; + ccs_pipe_t pipe2 = NULL; + + if (worklist_remove(&rpcmsg, &pipe, &buf, &serverStartTime)) { + uuid = ccs_win_pipe_getUuid(pipe); +#if 0 + cci_debug_printf("%s: processing WorkItem msg:%ld pipeUUID:<%s> pipeHandle:0x%X SST:%ld", + __FUNCTION__, rpcmsg, uuid, ccs_win_pipe_getHandle(pipe), serverStartTime); +#endif + if (serverStartTime <= getMySST()) { + switch (rpcmsg) { + case CCMSG_CONNECT: { + cci_debug_printf(" Processing CONNECT"); + rpcargs.uuid = (unsigned char*)uuid; + + // Even if a disconnect message is received before this code finishes, + // it won't be dequeued and processed until after this code finishes. + // So we can add the client after starting the connection listener. + connectionListener((void*)&rpcargs); + status = rpcargs.status; + + if (!status) { + status = ccs_server_add_client(pipe); + } + if (!status) {status = send_connection_reply(pipe);} + break; + } + case CCMSG_DISCONNECT: { + cci_debug_printf(" Processing DISCONNECT"); + if (!status) { + status = ccs_server_remove_client(pipe); + } + break; + } + case CCMSG_REQUEST: + cci_debug_printf(" Processing REQUEST"); + ccs_pipe_copy(&pipe2, pipe); + // Dispatch message here, setting both pipes to the client UUID: + err = ccs_server_handle_request (pipe, pipe2, buf); + break; + case CCMSG_PING: + cci_debug_printf(" Processing PING"); + err = krb5int_ipc_stream_new (&stream); + err = krb5int_ipc_stream_write(stream, "This is a test of the emergency broadcasting system", 52); + err = ccs_os_server_send_reply(pipe, stream); + break; + default: + cci_debug_printf("Huh? Received invalid message type %ld from UUID:<%s>", + rpcmsg, uuid); + break; + } + if (buf) krb5int_ipc_stream_release(buf); + /* Don't free uuid, which was allocated here. A pointer to it is in the + rpcargs struct which was passed to connectionListener which will be + received by ccapi_listen when the client exits. ccapi_listen needs + the uuid to know which client to disconnect. + */ + } + // Server's start time is different from what the client thinks. + // That means the server has rebooted since the client connected. + else { + cci_debug_printf("Whoops! Server has rebooted since client established connection."); + } + } + else {cci_debug_printf("Huh? Queue not empty but no item to remove.");} + } + } + + return cci_check_error (err); + } + +/* ------------------------------------------------------------------------ */ + +cc_int32 ccs_os_server_send_reply (ccs_pipe_t in_pipe, + k5_ipc_stream in_reply_stream) { + + /* ccs_pipe_t in_reply_pipe is a char* reply endpoint. + k5_ipc_stream in_reply_stream is the data to be sent. + */ + + cc_int32 err = 0; + char* uuid = ccs_win_pipe_getUuid(in_pipe); + HANDLE h = ccs_win_pipe_getHandle(in_pipe); + + if (!err) { + err = send_init(uuid); // Sets RPC handle to be used. + } + + if (!err) { + RpcTryExcept { + long status; + ccs_rpc_request_reply( // make call with user message + CCMSG_REQUEST_REPLY, /* Message type */ + (unsigned char*)&h, /* client's tspdata* */ + (unsigned char*)uuid, + getMySST(), + krb5int_ipc_stream_size(in_reply_stream), /* Length of buffer */ + (const unsigned char*)krb5int_ipc_stream_data(in_reply_stream), /* Data buffer */ + &status ); /* Return code */ + } + RpcExcept(1) { + cci_check_error(RpcExceptionCode()); + } + RpcEndExcept + } + + /* The calls to the remote procedures are complete. */ + /* Free whatever we allocated: */ + err = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); + + return cci_check_error (err); + } + + +/* Windows-specific routines: */ + +void Usage(const char* argv0) { + printf("Usage:\n"); + printf("%s [m maxcalls] [n mincalls] [f dontwait] [h|?]]\n", argv0); + printf(" CCAPI server process.\n"); + printf(" h|? whow usage message. <\n"); + } + +/* ------------------------------------------------------------------------ */ +/* The receive thread repeatedly issues RpcServerListen. + When a message arrives, it is handled in the RPC procedure. + */ +void receiveLoop(void* rpcargs) { + + struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs; + RPC_STATUS status = FALSE; + unsigned char* pszSecurity = NULL; + LPSTR endpoint = NULL; + LPSTR event_name = NULL; + PSECURITY_DESCRIPTOR psd = NULL; + HANDLE hEvent = 0; + Init::InitInfo info; + + cci_debug_printf("THREAD BEGIN: %s", __FUNCTION__); + + status = Init::Info(info); + + /* Build complete RPC endpoint using previous CCAPI implementation: */ + if (!status) { + if (!rcvargs->opts->pszEndpoint) { + if (!status) { + status = alloc_name(&endpoint, "ep", isNT()); + } + + if (!status) { + status = alloc_name(&event_name, "startup", isNT()); + } + + if (!status) { + hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name); + // We ignore any error opening the event because we do not know who started us. + // [Comment paraphrased from previous implementation, whence it was copied.] + } + } + else { + endpoint = rcvargs->opts->pszEndpoint; + } + } + + cci_debug_printf("%s Registering endpoint %s", __FUNCTION__, endpoint); + + if (!status && isNT()) { + status = alloc_own_security_descriptor_NT(&psd); + } + + if (!status) { + status = RpcServerUseProtseqEp(rcvargs->protocolSequence, + rcvargs->opts->cMaxCalls, + (RPC_CSTR)endpoint, + rcvargs->opts->bDontProtect ? 0 : psd); // SD + } + + if (!status) { + status = RpcServerRegisterAuthInfo(0, // server principal + RPC_C_AUTHN_WINNT, + 0, + 0); + } + + while (bListen && !status) { + cci_debug_printf("%s is listening ...", __FUNCTION__); + + if (!info.isNT) { + status = RpcServerRegisterIf(ccs_request_ServerIfHandle, // interface + NULL, // MgrTypeUuid + NULL); // MgrEpv; null means use default + } + else { + status = info.fRpcServerRegisterIfEx(ccs_request_ServerIfHandle, // interface + NULL, // MgrTypeUuid + NULL, // MgrEpv; 0 means default + RPC_IF_ALLOW_SECURE_ONLY, + rcvargs->opts->cMaxCalls, + rcvargs->opts->bSecCallback ? + (RPC_IF_CALLBACK_FN*)sec_callback : 0 ); + } + + if (!status) { + status = RpcServerListen(rcvargs->opts->cMinCalls, + rcvargs->opts->cMaxCalls, + rcvargs->opts->fDontWait); + } + + if (!status) { + if (rcvargs->opts->fDontWait) { + if (hEvent) SetEvent(hEvent); // Ignore any error -- SetEvent is an optimization. + status = RpcMgmtWaitServerListen(); + } + } + } + + if (status) { // Cleanup in case of errors: + if (hEvent) CloseHandle(hEvent); + free_alloc_p(&event_name); + free_alloc_p(&psd); + if (endpoint && (endpoint != rcvargs->opts->pszEndpoint)) + free_alloc_p(&endpoint); + } + + _endthread(); + } // End receiveLoop + + +#if 0 + + return status; +} +#endif + + + +/* ------------------------------------------------------------------------ */ +/* The connection listener thread waits forever for a call to the CCAPI_CLIENT_ + endpoint, ccapi_listen function to complete. If the call completes or gets an + RPC exception, it means the client has disappeared. + + A separate connectionListener is started for each client that has connected to the server. + */ + +void connectionListener(void* rpcargs) { + + struct RpcRcvArgs* rcvargs = (struct RpcRcvArgs*)rpcargs; + RPC_STATUS status = FALSE; + char* endpoint; + unsigned char* pszOptions = NULL; + unsigned char * pszUuid = NULL; + + endpoint = clientEndpoint((char*)rcvargs->uuid); + rpcState = (RPC_ASYNC_STATE*)malloc(sizeof(RPC_ASYNC_STATE)); + status = RpcAsyncInitializeHandle(rpcState, sizeof(RPC_ASYNC_STATE)); + cci_debug_printf(""); + cci_debug_printf("%s About to LISTEN to <%s>", __FUNCTION__, endpoint); + + rpcState->UserInfo = rcvargs->uuid; + rpcState->NotificationType = RpcNotificationTypeApc; + rpcState->u.APC.NotificationRoutine = clientListener; + rpcState->u.APC.hThread = 0; + + /* [If in use] Free previous binding: */ + if (bRpcHandleInited) { + // Free previous binding (could have been used to call ccapi_listen + // in a different client thread). + // Don't check result or update status. + RpcStringFree(&pszStringBinding); + RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); + bRpcHandleInited = FALSE; + } + + /* Set up binding to the client's endpoint: */ + if (!status) { + status = RpcStringBindingCompose( + pszUuid, + pszProtocolSequence, + pszNetworkAddress, + (RPC_CSTR)endpoint, + pszOptions, + &pszStringBinding); + } + + /* Set the binding handle that will be used to bind to the server. */ + if (!status) { + status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE); + } + if (!status) {bRpcHandleInited = TRUE;} + + RpcTryExcept { + cci_debug_printf(" Calling remote procedure ccapi_listen"); + ccapi_listen(rpcState, SERVER_REPLY_RPC_HANDLE, CCMSG_LISTEN, &status); + /* Asynchronous call will return immediately. */ + } + RpcExcept(1) { + status = cci_check_error(RpcExceptionCode()); + } + RpcEndExcept + + rcvargs->status = status; + } // End connectionListener + + +void RPC_ENTRY clientListener( + _RPC_ASYNC_STATE* pAsync, + void* Context, + RPC_ASYNC_EVENT Event + ) { + + ccs_pipe_t pipe = ccs_win_pipe_new((char*)pAsync->UserInfo, NULL); + + cci_debug_printf("%s(0x%X, ...) async routine for <0x%X:%s>!", + __FUNCTION__, pAsync, pAsync->UserInfo, pAsync->UserInfo); + + worklist_add( CCMSG_DISCONNECT, + pipe, + NULL, /* No payload with connect request */ + (const time_t)0 ); /* No server session number with connect request */ + } + + +void printError( TCHAR* msg ) { + DWORD eNum; + TCHAR sysMsg[256]; + TCHAR* p; + + eNum = GetLastError( ); + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, eNum, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + sysMsg, 256, NULL ); + + // Trim the end of the line and terminate it with a null + p = sysMsg; + while( ( *p > 31 ) || ( *p == 9 ) ) + ++p; + do { *p-- = 0; } while( ( p >= sysMsg ) && + ( ( *p == '.' ) || ( *p < 33 ) ) ); + + // Display the message + cci_debug_printf("%s failed with error %d (%s)", msg, eNum, sysMsg); + } + + +RPC_STATUS send_init(char* clientUUID) { + RPC_STATUS status; + unsigned char * pszUuid = NULL; + unsigned char * pszOptions = NULL; + + /* Use a convenience function to concatenate the elements of */ + /* the string binding into the proper sequence. */ + status = RpcStringBindingCompose(pszUuid, + pszProtocolSequence, + pszNetworkAddress, + (unsigned char*)clientEndpoint(clientUUID), + pszOptions, + &pszStringBinding); + if (status) {return (status);} + + /* Set the binding handle that will be used to bind to the RPC server [the 'client']. */ + status = RpcBindingFromStringBinding(pszStringBinding, &SERVER_REPLY_RPC_HANDLE); + return (status); + } + +RPC_STATUS send_finish() { + RPC_STATUS status; + /* Can't shut down client -- it runs listen function which */ + /* server uses to detect the client going away. */ + + /* The calls to the remote procedures are complete. */ + /* Free the string and the binding handle */ + status = RpcStringFree(&pszStringBinding); // remote calls done; unbind + if (status) {return (status);} + + status = RpcBindingFree(&SERVER_REPLY_RPC_HANDLE); // remote calls done; unbind + + return (status); + } + +RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe) { + char* uuid = ccs_win_pipe_getUuid (in_pipe); + HANDLE h = ccs_win_pipe_getHandle(in_pipe); + RPC_STATUS status = send_init(uuid); + + RpcTryExcept { + ccs_rpc_connect_reply( // make call with user message + CCMSG_CONNECT_REPLY, /* Message type */ + (unsigned char*)&h, /* client's tspdata* */ + (unsigned char*)uuid, + getMySST(), /* Server's session number = it's start time */ + &status ); /* Return code */ + } + RpcExcept(1) { + cci_check_error(RpcExceptionCode()); + } + RpcEndExcept + + status = send_finish(); + return (status); + } + +#if 0 +DWORD alloc_name(LPSTR* pname, LPSTR postfix) { + DWORD len = strlen(sessID) + 1 + strlen(postfix) + 1; + + *pname = (LPSTR)malloc(len); + if (!*pname) return GetLastError(); + _snprintf(*pname, len, "%s.%s", sessID, postfix); + return 0; + } +#endif + +RPC_STATUS GetPeerName( RPC_BINDING_HANDLE hClient, + LPTSTR pszClientName, + int iMaxLen) { + RPC_STATUS Status = RPC_S_OK; + RPC_BINDING_HANDLE hServer = NULL; + PTBYTE pszStringBinding = NULL; + PTBYTE pszClientNetAddr = NULL; + PTBYTE pszProtSequence = NULL; + + memset(pszClientName, 0, iMaxLen * sizeof(TCHAR)); + + __try { + // Create a partially bound server handle from the client handle. + Status = RpcBindingServerFromClient (hClient, &hServer); + if (Status != RPC_S_OK) __leave; + + // Get the partially bound server string binding and parse it. + Status = RpcBindingToStringBinding (hServer, + &pszStringBinding); + if (Status != RPC_S_OK) __leave; + + // String binding only contains protocol sequence and client + // address, and is not currently implemented for named pipes. + Status = RpcStringBindingParse (pszStringBinding, NULL, + &pszProtSequence, &pszClientNetAddr, + NULL, NULL); + if (Status != RPC_S_OK) + __leave; + int iLen = lstrlen(pszClientName) + 1; + if (iMaxLen < iLen) + Status = RPC_S_BUFFER_TOO_SMALL; + lstrcpyn(pszClientName, (LPCTSTR)pszClientNetAddr, iMaxLen); + } + __finally { + if (pszProtSequence) + RpcStringFree (&pszProtSequence); + + if (pszClientNetAddr) + RpcStringFree (&pszClientNetAddr); + + if (pszStringBinding) + RpcStringFree (&pszStringBinding); + + if (hServer) + RpcBindingFree (&hServer); + } + return Status; +} + +struct client_auth_info { + RPC_AUTHZ_HANDLE authz_handle; + unsigned char* server_principal; // need to RpcFreeString this + ULONG authn_level; + ULONG authn_svc; + ULONG authz_svc; +}; + +RPC_STATUS +GetClientId( + RPC_BINDING_HANDLE hClient, + char* client_id, + int max_len, + client_auth_info* info + ) +{ + RPC_AUTHZ_HANDLE authz_handle = 0; + unsigned char* server_principal = 0; + ULONG authn_level = 0; + ULONG authn_svc = 0; + ULONG authz_svc = 0; + RPC_STATUS status = 0; + + memset(client_id, 0, max_len); + + if (info) { + memset(info, 0, sizeof(client_auth_info)); + } + + status = RpcBindingInqAuthClient(hClient, &authz_handle, + info ? &server_principal : 0, + &authn_level, &authn_svc, &authz_svc); + if (status == RPC_S_OK) + { + if (info) { + info->server_principal = server_principal; + info->authz_handle = authz_handle; + info->authn_level = authn_level; + info->authn_svc = authn_svc; + info->authz_svc = authz_svc; + } + + if (authn_svc == RPC_C_AUTHN_WINNT) { + WCHAR* username = (WCHAR*)authz_handle; + int len = lstrlenW(username) + 1; + if (max_len < len) + status = RPC_S_BUFFER_TOO_SMALL; + _snprintf(client_id, max_len, "%S", username); + } else { + status = RPC_S_UNKNOWN_AUTHN_SERVICE; + } + } + return status; +} + +char* +rpc_error_to_string( + RPC_STATUS status + ) +{ + switch(status) { + case RPC_S_OK: + return "OK"; + case RPC_S_INVALID_BINDING: + return "Invalid binding"; + case RPC_S_WRONG_KIND_OF_BINDING: + return "Wrong binding"; + case RPC_S_BINDING_HAS_NO_AUTH: + RpcRaiseException(RPC_S_BINDING_HAS_NO_AUTH); + return "Binding has no auth"; + default: + return "BUG: I am confused"; + } +} + +void +print_client_info( + RPC_STATUS peer_status, + const char* peer_name, + RPC_STATUS client_status, + const char* client_id, + client_auth_info* info + ) +{ + if (peer_status == RPC_S_OK || peer_status == RPC_S_BUFFER_TOO_SMALL) { + cci_debug_printf("%s Peer Name is \"%s\"", __FUNCTION__, peer_name); + } else { + cci_debug_printf("%s Error %u getting Peer Name (%s)", + __FUNCTION__, peer_status, rpc_error_to_string(peer_status)); + } + + if (client_status == RPC_S_OK || client_status == RPC_S_BUFFER_TOO_SMALL) { + if (info) { + cci_debug_printf("%s Client Auth Info" + "\tServer Principal: %s\n" + "\tAuthentication Level: %d\n" + "\tAuthentication Service: %d\n" + "\tAuthorization Service: %d\n", + __FUNCTION__, + info->server_principal, + info->authn_level, + info->authn_svc, + info->authz_svc); + } + cci_debug_printf("%s Client ID is \"%s\"", __FUNCTION__, client_id); + } else { + cci_debug_printf("%s Error getting Client Info (%u = %s)", + __FUNCTION__, client_status, rpc_error_to_string(client_status)); + } +} + +DWORD sid_check() { + DWORD status = 0; + HANDLE hToken_c = 0; + HANDLE hToken_s = 0; + PTOKEN_USER ptu_c = 0; + PTOKEN_USER ptu_s = 0; + DWORD len = 0; + BOOL bImpersonate = FALSE; + + // Note GetUserName will fail while impersonating at identify + // level. The workaround is to impersonate, OpenThreadToken, + // revert, call GetTokenInformation, and finally, call + // LookupAccountSid. + + // XXX - Note: This workaround does not appear to work. + // OpenThreadToken fails with error 1346: "Either a requid + // impersonation level was not provided or the provided + // impersonation level is invalid". + + status = RpcImpersonateClient(0); + + if (!status) { + bImpersonate = TRUE; + if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken_c)) + status = GetLastError(); + } + + if (!status) { + status = RpcRevertToSelf(); + } + + if (!status) { + bImpersonate = FALSE; + + len = 0; + GetTokenInformation(hToken_c, TokenUser, ptu_c, 0, &len); + if (len == 0) status = 1; + } + + if (!status) { + if (!(ptu_c = (PTOKEN_USER)LocalAlloc(0, len))) + status = GetLastError(); + } + + if (!status) { + if (!GetTokenInformation(hToken_c, TokenUser, ptu_c, len, &len)) + status = GetLastError(); + } + + if (!status) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken_s)) + status = GetLastError(); + } + + if (!status) { + len = 0; + GetTokenInformation(hToken_s, TokenUser, ptu_s, 0, &len); + if (len == 0) status = GetLastError(); + } + + if (!status) { + if (!(ptu_s = (PTOKEN_USER)LocalAlloc(0, len))) + status = GetLastError(); + } + + if (!status) { + if (!GetTokenInformation(hToken_s, TokenUser, ptu_s, len, &len)) + status = GetLastError(); + } + + if (!EqualSid(ptu_s->User.Sid, ptu_c->User.Sid)) + status = RPC_S_ACCESS_DENIED; + +/* Cleanup: */ + if (!hToken_c && !bImpersonate) + cci_debug_printf("%s Cannot impersonate (%u)", __FUNCTION__, status); + else if (!hToken_c) + cci_debug_printf("%s Failed to open client token (%u)", __FUNCTION__, status); + else if (bImpersonate) + cci_debug_printf("%s Failed to revert (%u)", __FUNCTION__, status); + else if (!ptu_c) + cci_debug_printf("%s Failed to get client token user info (%u)", + __FUNCTION__, status); + else if (!hToken_s) + cci_debug_printf("%s Failed to open server token (%u)", __FUNCTION__, status); + else if (!ptu_s) + cci_debug_printf("%s Failed to get server token user info (%u)", + __FUNCTION__, status); + else if (status == RPC_S_ACCESS_DENIED) + cci_debug_printf("%s SID **does not** match!", __FUNCTION__); + else if (status == RPC_S_OK) + cci_debug_printf("%s SID matches!", __FUNCTION__); + else + if (status) { + cci_debug_printf("%s unrecognized error %u", __FUNCTION__, status); + abort(); + } + + if (bImpersonate) RpcRevertToSelf(); + if (hToken_c && hToken_c != INVALID_HANDLE_VALUE) + CloseHandle(hToken_c); + if (ptu_c) LocalFree(ptu_c); + if (hToken_s && hToken_s != INVALID_HANDLE_VALUE) + CloseHandle(hToken_s); + if (ptu_s) LocalFree(ptu_s); + if (status) cci_debug_printf("%s returning %u", __FUNCTION__, status); + return status; + } + +RPC_STATUS RPC_ENTRY sec_callback( IN RPC_IF_ID *Interface, + IN void *Context) { + char peer_name[1024]; + char client_name[1024]; + RPC_STATUS peer_status; + RPC_STATUS client_status; + + cci_debug_printf("%s", __FUNCTION__); + peer_status = GetPeerName(Context, peer_name, sizeof(peer_name)); + client_status = GetClientId(Context, client_name, sizeof(client_name), 0); + print_client_info(peer_status, peer_name, client_status, client_name, 0); + DWORD sid_status = sid_check(); + cci_debug_printf("%s returning (%u)", __FUNCTION__, sid_status); + return sid_status; + } + + + +/*********************************************************************/ +/* MIDL allocate and free */ +/*********************************************************************/ + +extern "C" void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) { + return(malloc(len)); + } + +extern "C" void __RPC_USER midl_user_free(void __RPC_FAR * ptr) { + free(ptr); + } + +/* stubs */ +extern "C" cc_int32 +ccs_os_notify_cache_collection_changed (ccs_cache_collection_t cc) +{ + return 0; +} + +extern "C" cc_int32 +ccs_os_notify_ccache_changed (ccs_cache_collection_t cc, const char *name) +{ + return 0; +} -- cgit