From: Jeffrey Altman Date: Mon, 5 Jun 2006 04:30:35 +0000 (+0000) Subject: more updates X-Git-Tag: krb5-1.6-alpha1~274^2~15 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=3d6591dd63c23bcc0ae68e94a960c85fd53daad0;p=krb5.git more updates git-svn-id: svn://anonsvn.mit.edu/krb5/branches/ccapi@18082 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/ccapi/NTMakefile b/src/lib/ccapi/NTMakefile new file mode 100644 index 000000000..57c42e337 --- /dev/null +++ b/src/lib/ccapi/NTMakefile @@ -0,0 +1,25 @@ +CD = cd + +all: + $(CD) common + $(MAKE) -f NTMakefile all + $(CD) ../client + $(MAKE) -f NTMakefile all + $(CD) ../server + $(MAKE) -f NTMakefile all + $(CD) ../windows + $(MAKE) -f NTMakefile all + $(CD) .. + +clean: + $(CD) common + $(MAKE) -f NTMakefile clean + $(CD) ../client + $(MAKE) -f NTMakefile clean + $(CD) ../server + $(MAKE) -f NTMakefile clean + $(CD) ../windows + $(MAKE) -f NTMakefile clean + $(CD) .. + + diff --git a/src/lib/ccapi/client/NTMakefile b/src/lib/ccapi/client/NTMakefile index f9d85b463..2ce87c350 100644 --- a/src/lib/ccapi/client/NTMakefile +++ b/src/lib/ccapi/client/NTMakefile @@ -1,6 +1,6 @@ !INCLUDE -CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsdll) +CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsmt) CC_CLIENT_OBJS = cacheapi.obj context.obj ccache.obj credentials.obj ccache_iterator.obj \ credentials_iterator.obj ccstring.obj ccapiv2.obj @@ -12,14 +12,7 @@ CC_COMMON_LIB = ..\common\cc_common.lib $(CC_CLIENT_LIB): $(CC_CLIENT_OBJS) $(implib) /NOLOGO /OUT:$@ $** -CCAPI_DLLFILE = krbcc32.dll - -WINLIBS = ws2_32.lib $(guilibsdll) msvcrt.lib - -$(CCAPI_DLLFILE): dllmain.obj $(CC_CLIENT_LIB) $(CC_COMMON_LIB) - $(link) /OUT:$@ $(ldebug) $(dlllflags) /NODEFAULTLIB:libcmt.lib -def:cacheapi.def $** $(WINLIBS) - -all: $(CCAPI_DLLFILE) +all: $(CC_CLIENT_LIB) clean: - del *.obj *.lib *.dll *.exp + del *.obj *.lib diff --git a/src/lib/ccapi/common/NTMakefile b/src/lib/ccapi/common/NTMakefile index d0d92fcbd..a43985af3 100644 --- a/src/lib/ccapi/common/NTMakefile +++ b/src/lib/ccapi/common/NTMakefile @@ -1,6 +1,6 @@ !INCLUDE -CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsdll) +CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsmt) CC_COMMON_OBJS = marshall.obj msg.obj generic_lists.obj diff --git a/src/lib/ccapi/doc/implementation-notes.txt b/src/lib/ccapi/doc/implementation-notes.txt new file mode 100644 index 000000000..e6150fb23 --- /dev/null +++ b/src/lib/ccapi/doc/implementation-notes.txt @@ -0,0 +1,156 @@ +The following are notes describing the requirements of the Platform +Specific code necessary for constructing a Portable CCAPI. + +Directory structure: + + lib/ccapi/client - platform independent client library + lib/ccapi/common - platform independent common library + lib/ccapi/include - platform independent header files + lib/ccapi/mac - macosx specific headers, libraries, executables + lib/ccapi/server - platform independent server library + lib/ccapi/windows - windows specific headers, libraries, executables + + +Platform Independent Design: + +The functionality of the Portable CCAPI is implemented in the platform +independent libraries. The common library encapsulates the functions +for managing generic lists, iterators, and messages as well as routines +formarshalling and unmarshalling. The client library provides the +client side routines for issuing requests to the ccapi server minus the +platform dependent glue required for shared library initialization, +cleanup, and interprocess communications. The server library provides +server side functionality for managing credential cache collections, +caches, credentials, iterators, and their handles minus the platform +dependent glue for process initialization, interprocess communication, +session security, and critical section enforcement. + + +Platform Dependent Design Requirements: + +The platform dependent code is responsible for producing a shared +client library: + + + the shared library is built from cc_client.lib and cc_common.lib plus + platform dependent glue + + - [windows] link cc_client.lib and cc_common.lib with platform + dependent routines and export list (.def) to produce + krbcc32.{lib,dll} + + + initialization and cleanup + + - [windows] provide DllMain entry point providing Process and Thread + attachment and detachment routines + + + implement cci_perform_rpc() function used by cc_client.lib + cc_int32 cci_perform_rpc(cc_msg_t *request, cc_msg_t **response) + + - cci_perform_rpc() takes an input request cc_msg_t object, flattens + it with cci_msg_flatten() and sends the contents of unsigned char + buffer request->flat of length request->flat_len to the server + utilizing a platform specific interprocess communication method. + + - upon IPC success, cci_perform_rpc() unflattens the response buffer + with cci_msg_unflatten() and returns the new cc_msg_t response + object to the caller. + + - cci_perform_rpc() is responsible for performing any necessary + session security management. For example, on Windows the Logon + Provider executes under the local machine's "SYSTEM" account within + session 0 and not under the account of the user that is logging in + nor within the session the user's desktop and applications will be + running within. It is the responsibility of cci_perform_rpc() and + the platform dependent IPC mechanism to communicate the user's + security identifiers to the server. + + For Windows, this means that the platform specific IPC messaging + allows a username and session identifier to be sent separate from + the username and session identifier that will be obtained via the + use of Local RPC. If the Local RPC authenticates the user as + "SYSTEM" and session 0, then the communicated values (if provided) + will be used instead. + + + implement client side of IPC routine. + + - [windows] the client side IPC routine is produced by compiling a + IDL file. The IDL defines an interface with a single function: + + __int32 ccapi_Message ( + [in] handle_t h, + [in, string] unsigned char * client_name, + [in] struct _LUID luid, + [in] __int32 in_len, + [in, string, size_is(in_len)] unsigned char * in_buf, + [in] __int32 out_size, + [out] __int32 * out_len, + [out, string, size_is(out_size)] unsigned char + out_buf[*]); + + The handle is a Local RPC specific handle used to identify the + request. The client_name and luid are the override values for the + username and session identifier for use during Windows login. The + rest of the parameters provide the input and output buffers as well + as allow communication of the actual length of the message data + that is required by cci_msg_unflatten(). + + + if the CCAPI server is per-session, the shared client library is + responsible for ensuring that an instance of the server is running in + the current session. If not, the library must initiate an instance + of the CCAPI server prior to performing any IPC requests. + +The platform dependent code is responsible for producing a server +executable: + + + The server executable is built from cc_server.lib and cc_common.lib + plus platform dependent glue. + + - [windows] The Windows CCAPI Server is being built using the + per-system model. The platform specific code is responsible for + providing NT Service Management routines for installation and + removal as well as the NT Service Entry Points used when the + process is started as an NT Service. + + link cc_server.lib and cc_common.lib with platform dependent + routines to produce krbcc32s.exe. + + + Based upon the platform requirements, the server may be constructed + to be per-session or per-system. The selected IPC mechanism must + enforce the appropriate scoping. + + + The platform dependent startup routines will perform platform + specific initialization including the IPC engine and call the + platform independent initialization routine ccs_serv_initialize() + + + The platform dependent shutdown routines will perform platform + specific cleanup including the IPC engine and call the platform + independent function ccs_serv_cleanup() prior to process termination. + + + For each inbound CCAPI request, the server will unmarshall the + request using cci_msg_unflatten() to produce a cc_msg_t object, + construct cc_auth_info_t and cc_session_info_t objects to represent + the platform dependent authentication and session data, call + ccs_serv_process_msg() to process the request, call cci_msg_flatten() + to marhall the response, transmit the response to the caller, and + then cleanup the request and response cc_msg_t objects with + cci_msg_destroy(). + + + The cc_auth_info_t and cc_session_info_t objects are structures + storing opaque binary (data, length) representations of the + authentication and session data. These are stored as part of ccache + collection and ccaches. ccs_serv_process_msg() will perform a binary + comparison of the stored data with the data provided in the current + request. If they do not match, the request will be denied. It is + necessary that the data generated data always be the same. If + username strings are not case-sensitive, they should be normalized + before being passed to ccs_serv_process_msg(). + + + The current cc_server.lib routines assume that one request at a time + is being processed. If the IPC engine allows for more than one + request to be simultaneously received in separate threads, then the + call to ccs_serv_process_msg() must be wrapped by a critical section. + Future enhancements to cc_server.lib will allow for per-object + mutexes. When available the platform specific glue must provide + functions to create, obtain, release, and destroy mutex objects. + + diff --git a/src/lib/ccapi/include/CredentialsCache.h b/src/lib/ccapi/include/CredentialsCache.h index 7143da4e2..12748bb9d 100644 --- a/src/lib/ccapi/include/CredentialsCache.h +++ b/src/lib/ccapi/include/CredentialsCache.h @@ -69,6 +69,10 @@ #include #endif +#if defined(_WIN32) +#include +#endif + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/src/lib/ccapi/include/CredentialsCache2.h b/src/lib/ccapi/include/CredentialsCache2.h index 214d93a02..706c86913 100644 --- a/src/lib/ccapi/include/CredentialsCache2.h +++ b/src/lib/ccapi/include/CredentialsCache2.h @@ -87,10 +87,10 @@ typedef struct cc_credentials_v5_compat { char* client; char* server; cc_data_compat keyblock; - cc_time_t authtime; - cc_time_t starttime; - cc_time_t endtime; - cc_time_t renew_till; + cc_time authtime; + cc_time starttime; + cc_time endtime; + cc_time renew_till; cc_uint32 is_skey; cc_uint32 ticket_flags; cc_data_compat** addresses; @@ -185,6 +185,13 @@ enum { CC_CRED_MAX }; +enum { + CC_LOCK_UNLOCK = 1, + CC_LOCK_READER = 2, + CC_LOCK_WRITER = 3, + CC_LOCK_NOBLOCK = 16 +}; + CCACHE_API cc_int32 cc_shutdown ( apiCB** ioContext); @@ -194,7 +201,7 @@ CCACHE_API cc_int32 cc_get_NC_info ( CCACHE_API cc_int32 cc_get_change_time ( apiCB* inContext, - cc_time_t* outTime); + cc_time* outTime); CCACHE_API cc_int32 cc_open ( apiCB* inContext, @@ -293,6 +300,11 @@ CCACHE_API cc_int32 cc_free_NC_info ( apiCB* inContext, infoNC*** ioInfo); +CCACHE_API cc_int32 cc_lock_request( + apiCB* inContext, + const ccache_p* inCCache, + const cc_int32 lock_type); + #if TARGET_OS_MAC #if defined(__MWERKS__) #pragma enumsalwaysint reset diff --git a/src/lib/ccapi/server/datastore.h b/src/lib/ccapi/include/datastore.h similarity index 100% rename from src/lib/ccapi/server/datastore.h rename to src/lib/ccapi/include/datastore.h diff --git a/src/lib/ccapi/server/rpc_auth.h b/src/lib/ccapi/include/rpc_auth.h similarity index 100% rename from src/lib/ccapi/server/rpc_auth.h rename to src/lib/ccapi/include/rpc_auth.h diff --git a/src/lib/ccapi/server/NTMakefile b/src/lib/ccapi/server/NTMakefile index b221bcb94..564097c53 100644 --- a/src/lib/ccapi/server/NTMakefile +++ b/src/lib/ccapi/server/NTMakefile @@ -1,18 +1,21 @@ -# Makefile for the CCAPI Generic Server +# Makefile for the CCAPI Server Library !INCLUDE -CFLAGS = -I../include +CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsmt) -CCAPI_LIB = ../client/ccapi.lib -WINLIBS = user32.lib advapi32.lib -CCSOBJS = ccs_context.obj ccs_ccache.obj ccs_lists.obj rpc_auth.obj serv_ops.obj +CC_SERVER_OBJS = ccs_context.obj ccs_ccache.obj ccs_lists.obj rpc_auth.obj serv_ops.obj -all: ccapi_server.exe +CC_SERVER_LIB = cc_server.lib -ccapi_server.exe: main.obj $(CCSOBJS) $(CCAPI_LIB) - link -out:$@ main.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS) +CC_COMMON_LIB = ../common/cc_common.lib + +$(CC_SERVER_LIB): $(CC_SERVER_OBJS) + $(implib) /NOLOGO /OUT:$@ $** + +all: $(CC_SERVER_LIB) clean: - del *.obj *.exe + del *.obj *.lib + \ No newline at end of file diff --git a/src/lib/ccapi/unit-test/NTMakefile b/src/lib/ccapi/unit-test/NTMakefile index eb2fd53e2..9bb486b6d 100644 --- a/src/lib/ccapi/unit-test/NTMakefile +++ b/src/lib/ccapi/unit-test/NTMakefile @@ -1,30 +1,48 @@ -# Makefile for the CCAPI Generic Server +!include -!INCLUDE +CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsmt) -CFLAGS = -I../include +WINLIBS = ws2_32.lib rpcrt4.lib $(guilibsdll) -CCAPI_LIB = ../lib/ccapi.lib -WINLIBS = user32.lib advapi32.lib -CCSOBJS = context.obj ccache.obj lists.obj rpc_auth.obj serv_ops.obj +T_CCACHE = t_ccache.exe -all: t_lists.exe t_msg.exe t_ccache.exe t_context.exe ccapi_server.exe +T_CONTEXT = t_context.exe -t_lists.exe: t_lists.obj $(CCSOBJS) $(CCAPI_LIB) - link -out:$@ t_lists.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS) +T_LISTS = t_lists.exe -t_msg.exe: t_msg.obj $(CCSOBJS) $(CCAPI_LIB) - link -out:$@ t_msg.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS) +T_MSG = t_msg.exe -t_ccache.exe: t_ccache.obj $(CCSOBJS) $(CCAPI_LIB) - link -out:$@ t_ccache.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS) +T_SERVER = t_server.exe -t_context.exe: t_context.obj $(CCSOBJS) $(CCAPI_LIB) - link -out:$@ t_context.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS) +all: $(T_CCACHE) $(T_CONTEXT) $(T_LISTS) $(T_MSG) $(T_SERVER) -ccapi_server.exe: main.obj $(CCSOBJS) $(CCAPI_LIB) - link -out:$@ main.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS) +ntccrpc_c.c ntccrpc_s.c ntccrpc.h: ntccrpc.idl ntccrpc.acf + midl ntccrpc.idl /acf ntccrpc.acf + +CC_CLIENT_LIB = ..\client\cc_client.lib + +CC_COMMON_LIB = ..\common\cc_common.lib + +CC_SERVER_LIB = ..\server\cc_server.lib + +CC_API_LIB = ..\windows\krbcc32.lib + +$(T_CCACHE): t_ccache.obj $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +$(T_CONTEXT): t_context.obj $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +$(T_LISTS): t_lists.obj $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +$(T_MSG): t_msg.obj $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +$(T_SERVER): t_server.obj $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +clean: + del *.exe *.dll *.lib *.exp *.obj ntccrpc_c.c ntccrpc_s.c ntccrpc.h -clean: - del *.obj *.exe diff --git a/src/lib/ccapi/unit-test/t_ccache.c b/src/lib/ccapi/unit-test/t_ccache.c index 6ef33ea23..175764e79 100644 --- a/src/lib/ccapi/unit-test/t_ccache.c +++ b/src/lib/ccapi/unit-test/t_ccache.c @@ -59,8 +59,8 @@ int main() { int i; cc_int32 code; - code = cci_ccache_new("The first", p1, cc_credentials_v4_v5, &c1); - code = cci_ccache_new("The 2nd", p2, cc_credentials_v4_v5, &c2); + code = ccs_ccache_new("The first", p1, cc_credentials_v4_v5, &c1); + code = ccs_ccache_new("The 2nd", p2, cc_credentials_v4_v5, &c2); cred1 = (cc_server_credentials_t*)malloc(sizeof(cc_server_credentials_t)); memset(cred1,0,sizeof(cc_server_credentials_t)); @@ -83,30 +83,30 @@ int main() { strncpy(cred2->creds.credentials.credentials_v4->principal, p1, strlen(p1)); cred3->creds.credentials.credentials_v5->client = p1; - code = cci_ccache_store_creds(c1, &cred1->creds); + code = ccs_ccache_store_creds(c1, &cred1->creds); printf("(c1, cred1) -> %d\n",code); - code = cci_ccache_store_creds(c1, &cred2->creds); + code = ccs_ccache_store_creds(c1, &cred2->creds); printf("(c1, cred2) -> %d\n",code); - code = cci_ccache_store_creds(c2, &cred3->creds); + code = ccs_ccache_store_creds(c2, &cred3->creds); printf("(c2, cred3) -> %d\n",code); - code = cci_ccache_store_creds(c1, &cred3->creds); + code = ccs_ccache_store_creds(c1, &cred3->creds); printf("(c1, cred3) -> %d\n",code); i = 0; - code = cci_ccache_move(c1, c2); - code = cci_ccache_destroy(c1); - code = cci_ccache_new_iterator(c2, &iterator); - while (cci_credentials_iterate_has_next(iterator)) { + code = ccs_ccache_move(c1, c2); + code = ccs_ccache_destroy(c1); + code = ccs_ccache_new_iterator(c2, &iterator); + while (ccs_credentials_iterate_has_next(iterator)) { i++; - code = cci_credentials_iterate_next(iterator, &node); + code = ccs_credentials_iterate_next(iterator, &node); stored_cred = (cc_server_credentials_t *)node->data; printf("%d %d %s\n", stored_cred->is_default, stored_cred->creds.version, stored_cred->creds.credentials.credentials_v4->principal); if (i == 1) { - code = cci_ccache_rem_creds(c2,&cred2->creds); + code = ccs_ccache_rem_creds(c2,&cred2->creds); printf("(c2 rem cred2) -> %d\n",code); } } diff --git a/src/lib/ccapi/unit-test/t_context.c b/src/lib/ccapi/unit-test/t_context.c index 9e35d9abf..d76ff78d9 100644 --- a/src/lib/ccapi/unit-test/t_context.c +++ b/src/lib/ccapi/unit-test/t_context.c @@ -68,10 +68,10 @@ int main() { int i; cc_int32 code; - code = cci_context_new(5, auth_info, session_info, &ctx); - code = cci_context_create_default_ccache(ctx, cc_credentials_v4, "Spike", &ccache); - code = cci_context_get_default_ccache_name(ctx, &name); - code = cci_context_open_ccache(ctx, name, &ccache); + code = ccs_context_new(5, auth_info, session_info, &ctx); + code = ccs_context_create_default_ccache(ctx, cc_credentials_v4, "Spike", &ccache); + code = ccs_context_get_default_ccache_name(ctx, &name); + code = ccs_context_open_ccache(ctx, name, &ccache); for (i = 0; i < 5; i++) { creds = (cc_credentials_union*)malloc(sizeof(cc_credentials_union)); @@ -79,32 +79,32 @@ int main() { creds->credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t)); strcpy(creds->credentials.credentials_v4->principal, "Spike"); - code = cci_ccache_store_creds(ccache, creds); + code = ccs_ccache_store_creds(ccache, creds); } - code = cci_context_create_ccache(ctx, "ccache 2", cc_credentials_v4, "Jeff", &ccache); - code = cci_context_open_ccache(ctx, "ccache 2", &ccache); + code = ccs_context_create_ccache(ctx, "ccache 2", cc_credentials_v4_v5, "Jeff", &ccache); + code = ccs_context_open_ccache(ctx, "ccache 2", &ccache); for (i = 0; i < 5; i++) { creds = (cc_credentials_union*)malloc(sizeof(cc_credentials_union)); - creds->version = cc_credentials_v4; - creds->credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t)); - strcpy(creds->credentials.credentials_v4->principal, "Jeff"); + creds->version = cc_credentials_v5; + creds->credentials.credentials_v5 = (cc_credentials_v5_t*)malloc(sizeof(cc_credentials_v5_t)); + strcpy(creds->credentials.credentials_v5->principal, "Jeff"); - cci_ccache_store_creds(ccache, creds); + ccs_ccache_store_creds(ccache, creds); } - code = cci_context_ccache_iterator(ctx, &ccache_iterator); - while (cci_ccache_iterate_has_next(ccache_iterator)) { - code = cci_ccache_iterate_next(ccache_iterator, &ccache_node); + code = ccs_context_ccache_iterator(ctx, &ccache_iterator); + while (ccs_ccache_iterate_has_next(ccache_iterator)) { + code = ccs_ccache_iterate_next(ccache_iterator, &ccache_node); ccache = (cc_server_ccache_t *)ccache_node->data; printf("%x for %s %s default = %d v %d\n", ccache, ccache->principal_v4, ccache->principal_v5, ccache->is_default, ccache->versions); - code = cci_ccache_new_iterator(ccache, &creds_iterator); - while (cci_credentials_iterate_has_next(creds_iterator)) { - code = cci_credentials_iterate_next(creds_iterator, &creds_node); + code = ccs_ccache_new_iterator(ccache, &creds_iterator); + while (ccs_credentials_iterate_has_next(creds_iterator)) { + code = ccs_credentials_iterate_next(creds_iterator, &creds_node); server_creds = (cc_server_credentials_t *)creds_node->data; printf("\t%s %d\n", server_creds->creds.credentials.credentials_v4->principal, diff --git a/src/lib/ccapi/unit-test/t_server.c b/src/lib/ccapi/unit-test/t_server.c index d4d998466..d6093941e 100644 --- a/src/lib/ccapi/unit-test/t_server.c +++ b/src/lib/ccapi/unit-test/t_server.c @@ -143,7 +143,7 @@ main(void) cc_session_info_t * session_info; cc_int32 code; - if ( cci_serv_initialize() != ccNoError ) + if ( ccs_serv_initialize() != ccNoError ) return 1; while ( 1 ) { @@ -163,7 +163,7 @@ main(void) code = obtain_session_info(&session_info); /* process message */ - code = cci_serv_process_msg(msg, auth_info, session_info, &resp); + code = ccs_serv_process_msg(msg, auth_info, session_info, &resp); /* flatten response */ code = cci_msg_flatten(resp, NULL); diff --git a/src/lib/ccapi/windows/NTMakefile b/src/lib/ccapi/windows/NTMakefile new file mode 100644 index 000000000..f6fee6f68 --- /dev/null +++ b/src/lib/ccapi/windows/NTMakefile @@ -0,0 +1,35 @@ +!include + +CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsmt) + +CCAPI_SERVER = ccapi_server.exe + +CCAPI_DLLFILE = krbcc32.dll + +WINLIBS = ws2_32.lib rpcrt4.lib $(guilibsdll) + +all: $(CCAPI_DLLFILE) $(CCAPI_SERVER) + +ntccrpc_c.c ntccrpc_s.c ntccrpc.h: ntccrpc.idl ntccrpc.acf + midl ntccrpc.idl /acf ntccrpc.acf + +CLIENT_OBJS = ntccrpc_c.obj client.obj dllmain.obj + +SERVER_OBJS = ntccrpc_s.obj server.obj + +CC_CLIENT_LIB = ..\client\cc_client.lib + +CC_COMMON_LIB = ..\common\cc_common.lib + +CC_SERVER_LIB = ..\server\cc_server.lib + +$(CCAPI_DLLFILE): $(CLIENT_OBJS) $(CC_CLIENT_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO /OUT:$@ $(ldebug) $(dlllflags) $(guilibsmt) -def:cacheapi.def $** $(WINLIBS) + +$(CCAPI_SERVER): $(SERVER_OBJS) $(CC_SERVER_LIB) $(CC_COMMON_LIB) + $(link) /NOLOGO $(conlibsmt) $(ldebug) $(conlflags) /OUT:$@ $** $(WINLIBS) + +clean: + del *.exe *.dll *.lib *.exp *.obj ntccrpc_c.c ntccrpc_s.c ntccrpc.h + + diff --git a/src/lib/ccapi/client/cacheapi.def b/src/lib/ccapi/windows/cacheapi.def similarity index 100% rename from src/lib/ccapi/client/cacheapi.def rename to src/lib/ccapi/windows/cacheapi.def diff --git a/src/lib/ccapi/windows/client.c b/src/lib/ccapi/windows/client.c new file mode 100644 index 000000000..db0b63aec --- /dev/null +++ b/src/lib/ccapi/windows/client.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include "ntccrpc.h" +#include +#include "CredentialsCache.h" +#include "msg.h" + +static RPC_BINDING_HANDLE hRpcBinding; + +void * __RPC_USER MIDL_user_allocate(size_t s) { + return malloc(s); +} + +void __RPC_USER MIDL_user_free(void * p) { + free(p); +} + +int cc_rpc_init(void) { + RPC_STATUS status; + TCHAR * bindstring = NULL; + RPC_SECURITY_QOS sqos; + + status = RpcStringBindingCompose(NULL, + _T("ncalrpc"), + NULL, + NULL, + NULL, + &bindstring); + + if (status != RPC_S_OK) { + fprintf(stderr, "RpcStringBindingCompose failed: %d\n", + status); + return 1; + } + + status = RpcBindingFromStringBinding(bindstring, + &hRpcBinding); + + if (status != RPC_S_OK) { + fprintf(stderr, "RpcBindingFromStringBinding failed: %d\n", + status); + return 1; + } + + status = RpcStringFree(&bindstring); + + ZeroMemory(&sqos, sizeof(sqos)); + + sqos.Version = 1; + sqos.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT; + sqos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC; + sqos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE; + + status = RpcBindingSetAuthInfoEx(hRpcBinding, + NULL, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_AUTHN_WINNT, + NULL, + 0, + &sqos); + if (status != RPC_S_OK) { + fprintf(stderr, "RpcBindingSetAuthInfoEx failed: %d\n", + status); + return 1; + } + + return 0; +} + +int cc_rpc_cleanup(void) { + RPC_STATUS status; + + status = RpcBindingFree(&hRpcBinding); + + return 0; +} + +cc_int32 cci_set_thread_session_id(unsigned char * client_name, LUID luid) { + +} + +void cci_get_thread_session_id(unsigned char * client_name, int len, LUID *pluid) { + +} + + +/* __int32 ccapi_Message( + * [in] handle_t h, + * [string][in] unsigned char *client_name, + * [in] struct _LUID luid, + * [in] __int32 cb_buffer, + * [out] __int32 *cb_len, + * [size_is][string][out] unsigned char buffer[ ]); + */ + +cc_int32 cci_perform_rpc(cc_msg_t *request, cc_msg_t **response) +{ + __int32 rpc_code; + unsigned char client_name[256]; + LUID luid; + struct __LUID __luid; + unsigned char out_buf[MAXMSGLEN]; + __int32 out_len = MAXMSGLEN; + + if (!cc_rpc_init()) + return -1; + + cci_get_thread_session_id(client_name, sizeof(client_name), &luid); + + __luid.HighPart = luid.HighPart; + __luid.LowPart = luid.LowPart; + + rpc_code = ccapi_Message(hRpcBinding, client_name, __luid, + request->flat, request->flat_len, + out_buf, &out_len); + + return rpc_code; +} diff --git a/src/lib/ccapi/client/dllmain.c b/src/lib/ccapi/windows/dllmain.c similarity index 100% rename from src/lib/ccapi/client/dllmain.c rename to src/lib/ccapi/windows/dllmain.c diff --git a/src/lib/ccapi/windows/ntccrpc.acf b/src/lib/ccapi/windows/ntccrpc.acf new file mode 100644 index 000000000..77216a9ea --- /dev/null +++ b/src/lib/ccapi/windows/ntccrpc.acf @@ -0,0 +1,8 @@ +[ + explicit_handle +] + +interface portable_ccapi +{ + +} \ No newline at end of file diff --git a/src/lib/ccapi/windows/ntccrpc.idl b/src/lib/ccapi/windows/ntccrpc.idl new file mode 100644 index 000000000..0dd038f6f --- /dev/null +++ b/src/lib/ccapi/windows/ntccrpc.idl @@ -0,0 +1,31 @@ +[ + uuid(c8b4a635-e9e4-4650-a073-b25610324950), + version(1.0), + endpoint("ncalrpc:[mit_nt_ccapi]"), + pointer_default(unique) +] + +interface portable_ccapi +{ + const short MAXMSGLEN = 65536; + + // Locally Unique Identifier + // + + struct __LUID { + __int32 LowPart; + long HighPart; + }; + + + // The Generic CCAPI Message RPC + + __int32 ccapi_Message ( + [in] handle_t h, + [in, string] unsigned char * client_name, + [in] struct __LUID luid, + [in, length_is(in_len), size_is(MAXMSGLEN)] unsigned char in_buf[], + [in] __int32 in_len, + [out, length_is(*out_len), size_is(MAXMSGLEN)] unsigned char out_buf[], + [out] __int32 * out_len); +} diff --git a/src/lib/ccapi/windows/server.c b/src/lib/ccapi/windows/server.c new file mode 100644 index 000000000..5ce8e6ebe --- /dev/null +++ b/src/lib/ccapi/windows/server.c @@ -0,0 +1,638 @@ + + +#include +#include "msg.h" +#include "marshall.h" +#include "serv_ops.h" +#include "datastore.h" +#include +#include +#include +#include +#include +#include "ntccrpc.h" +#include + +#define SVCNAME "MIT_CCAPI_NT_Service" + +SERVICE_STATUS_HANDLE h_service_status = NULL; +SERVICE_STATUS service_status; +FILE * logfile = NULL; + +/* Log File */ +void begin_log(void) { + char temppath[512]; + + temppath[0] = L'\0'; + + GetTempPathA(sizeof(temppath), temppath); + StringCbCatA(temppath, sizeof(temppath), "mit_nt_ccapi.log"); + logfile = fopen(temppath, "w"); +} + +void end_log(void) { + if (logfile) { + fclose(logfile); + logfile = NULL; + } +} + +BOOL report_status(DWORD state, + DWORD exit_code, + DWORD wait_hint) { + static DWORD checkpoint = 1; + BOOL rv = TRUE; + + if (state == SERVICE_START_PENDING) + service_status.dwControlsAccepted = 0; + else + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + service_status.dwCurrentState = state; + service_status.dwWin32ExitCode = exit_code; + service_status.dwWaitHint = wait_hint; + + if (state == SERVICE_RUNNING || + state == SERVICE_STOPPED) + service_status.dwCheckPoint = 0; + else + service_status.dwCheckPoint = checkpoint++; + + rv = SetServiceStatus(h_service_status, &service_status); + + return rv; +} + +void service_start(DWORD argc, LPTSTR * argv) { + RPC_STATUS status; + RPC_BINDING_VECTOR * bv; + + status = RpcServerUseProtseq("ncalrpc", + RPC_C_PROTSEQ_MAX_REQS_DEFAULT, + NULL); + + if (status != RPC_S_OK) { + return; + } + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerRegisterIf(portable_ccapi_v1_0_s_ifspec, + 0, 0); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerInqBindings(&bv); + + if (status != RPC_S_OK) + return; + + status = RpcEpRegister(portable_ccapi_v1_0_s_ifspec, + bv, 0, 0); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerRegisterAuthInfo(NULL, + RPC_C_AUTHN_WINNT, + 0, 0); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + status = RpcServerListen(1, + RPC_C_LISTEN_MAX_CALLS_DEFAULT, + TRUE); + + if (status != RPC_S_OK) + return; + + report_status(SERVICE_RUNNING, NO_ERROR, 0); + + begin_log(); + + status = RpcMgmtWaitServerListen(); + + end_log(); + + RpcEpUnregister(portable_ccapi_v1_0_s_ifspec, bv, 0); + + RpcBindingVectorFree(&bv); +} + +void service_stop(void) { + RpcMgmtStopServerListening(0); +} + +void * __RPC_USER MIDL_user_allocate(size_t s) { + return malloc(s); +} + +void __RPC_USER MIDL_user_free(void * p) { + free(p); +} + +typedef struct tag_client_info { + char client_name[512]; + LUID luid; +} client_info_t; + +int obtain_auth_info(client_info_t * client_info, cc_auth_info_t ** pauth_info) +{ + *pauth_info = (cc_auth_info_t *)malloc(sizeof(cc_auth_info_t)); + if ( !*pauth_info ) + return ccErrNoMem; + + (*pauth_info)->len = strlen(client_info->client_name) + 1; + (*pauth_info)->info = malloc((*pauth_info)->len); + if ( !(*pauth_info)->info ) { + free(*pauth_info); + return ccErrNoMem; + } + + memcpy((*pauth_info)->info, client_info->client_name, (*pauth_info)->len); + + return 0; +} + +void destroy_auth_info(cc_auth_info_t *auth_info) +{ + free(auth_info->info); + free(auth_info); +} + +int obtain_session_info(client_info_t * client_info, cc_session_info_t ** psession_info) +{ + *psession_info = (cc_session_info_t *)malloc(sizeof(cc_session_info_t)); + if ( !*psession_info ) + return ccErrNoMem; + + (*psession_info)->len = sizeof(LUID); + (*psession_info)->info = malloc((*psession_info)->len); + if ( !(*psession_info)->info ) { + free(*psession_info); + return ccErrNoMem; + } + + memcpy((*psession_info)->info, &client_info->luid, (*psession_info)->len); + + return 0; +} + +void destroy_session_info(cc_session_info_t *session_info) +{ + free(session_info->info); + free(session_info); +} + +RPC_STATUS check_auth(handle_t h, client_info_t * client_info) { + RPC_BINDING_HANDLE bh = (RPC_BINDING_HANDLE) h; + RPC_STATUS status; + HANDLE htoken = NULL; + char name[256]; + char domain[256]; + DWORD name_len; + DWORD domain_len; + SID_NAME_USE snu = 0; + + struct { + TOKEN_ORIGIN origin; + char pad[512]; + } torigin; + + struct { + TOKEN_OWNER owner; + char pad[4096]; + } towner; + + DWORD len; + + status = RpcImpersonateClient(bh); + + if (status != RPC_S_OK) + return status; + + if (!OpenThreadToken(GetCurrentThread(), + TOKEN_READ | TOKEN_QUERY_SOURCE, + FALSE, + &htoken)) { + status = GetLastError(); + goto _cleanup; + } + + len = 0; + + if (!GetTokenInformation(htoken, + TokenOrigin, + &torigin.origin, + sizeof(torigin), + &len)) { + status = GetLastError(); + goto _cleanup; + } + + if (!GetTokenInformation(htoken, + TokenOwner, + &towner.owner, + sizeof(towner), + &len)) { + status = GetLastError(); + goto _cleanup; + } + + + name_len = sizeof(name)/sizeof(name[0]); + domain_len = sizeof(domain)/sizeof(domain[0]); + + if (!LookupAccountSidA(NULL, + towner.owner.Owner, + name, + &name_len, + domain, + &domain_len, + &snu)) { + status = GetLastError(); + goto _cleanup; + } + + client_info->luid = torigin.origin.OriginatingLogonSession; + StringCbPrintfA(client_info->client_name, + sizeof(client_info->client_name), + "%s\\%s", domain, name); + + status = 0; + + _cleanup: + + RpcRevertToSelf(); + + return status; +} + +__int32 ccapi_Message( + /* [in] */ handle_t h, + /* [string][in] */ unsigned char *client_name, + /* [in] */ struct __LUID luid, + /* [size_is][length_is][in] */ unsigned char in_buf[], + /* [in] */ __int32 in_len, + /* [size_is][length_is][out] */ unsigned char out_buf[], + /* [out] */ __int32 *out_len) +{ + client_info_t client_info; + cc_msg_t * msg; + cc_msg_t * resp; + cc_auth_info_t * auth_info; + cc_session_info_t * session_info; + cc_int32 code; + + if ( ccs_serv_initialize() != ccNoError ) { + code = ccErrServerUnavailable; + goto done; + } + + code = check_auth(h, &client_info); + if (code == 0) { + if (!strcmp("SYSTEM",client_info.client_name) && + client_info.luid.HighPart == 0 && + client_info.luid.LowPart == 0 && + client_name != NULL && + client_name[0] != '\0') { + StringCbPrintfA(client_info.client_name, + sizeof(client_info.client_name), + "%s", client_name); + client_info.luid.HighPart = luid.HighPart; + client_info.luid.LowPart = luid.LowPart; + } + } else { + code = ccErrServerCantBecomeUID; + goto done; + } + + /* allocate message */ + msg = (cc_msg_t *)malloc(sizeof(cc_msg_t)); + if (!msg) { + code = ccErrNoMem; + goto done; + } + + /* unflatten message */ + code = cci_msg_unflatten(in_buf, in_len, &msg); + if (code) + goto cleanup; + + /* obtain auth info */ + code = obtain_auth_info(&client_info, &auth_info); + if (code) + goto cleanup; + + /* obtain session info */ + code = obtain_session_info(&client_info, &session_info); + if (code) + goto cleanup; + + /* process message */ + code = ccs_serv_process_msg(msg, auth_info, session_info, &resp); + if (code) + goto cleanup; + + /* flatten response */ + code = cci_msg_flatten(resp, NULL); + if (code) + goto cleanup; + + /* send response */ + if (resp->flat_len > MAXMSGLEN) { + code = ccErrBadInternalMessage; + goto cleanup; + } + memcpy(out_buf, resp->flat, resp->flat_len); + *out_len = resp->flat_len; + code = ccNoError; + + cleanup: + if (auth_info) + destroy_auth_info(auth_info); + + if (session_info) + destroy_session_info(session_info); + + /* free message */ + if (msg) + cci_msg_destroy(msg); + + /* free response */ + if (resp) + cci_msg_destroy(resp); + + done: + return code ? -1 : 0; +} + +void WINAPI service_control(DWORD ctrl_code) { + switch(ctrl_code) { + case SERVICE_CONTROL_STOP: + report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); + service_stop(); + return; + + /* everything else falls through */ + } + + report_status(service_status.dwCurrentState, NO_ERROR, 0); +} + +void WINAPI service_main(DWORD argc, LPTSTR * argv) { + + h_service_status = RegisterServiceCtrlHandler( _T(SVCNAME), service_control); + + if (!h_service_status) + goto cleanup; + + ZeroMemory(&service_status, sizeof(service_status)); + + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + service_status.dwServiceSpecificExitCode = 0; + + if (!report_status(SERVICE_START_PENDING, + NO_ERROR, + 3000)) + goto cleanup; + + service_start(argc, argv); + + cleanup: + + if (h_service_status) { + report_status(SERVICE_STOPPED, NO_ERROR, 0); + } +} + + +BOOL +IsInstalled() +{ + BOOL bResult = FALSE; + SC_HANDLE hSCM; + SC_HANDLE hService; + + // Open the Service Control Manager + hSCM = OpenSCManager( NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access + if (hSCM) { + + // Try to open the service + hService = OpenService( hSCM, + SVCNAME, + SERVICE_QUERY_CONFIG); + if (hService) { + bResult = TRUE; + CloseServiceHandle(hService); + } + + CloseServiceHandle(hSCM); + } + + return bResult; +} + +BOOL +Install() +{ + char szFilePath[_MAX_PATH]; + SC_HANDLE hSCM; + SC_HANDLE hService; + TCHAR szKey[256]; + HKEY hKey = NULL; + DWORD dwData; + + // Open the Service Control Manager + hSCM = OpenSCManager( NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access + if (!hSCM) + return FALSE; + + // Get the executable file path + GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); + + // Create the service + hService = CreateService( hSCM, + SVCNAME, + SVCNAME, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, // start condition + SERVICE_ERROR_NORMAL, + szFilePath, + NULL, + NULL, + NULL, + NULL, + NULL); + if (!hService) { + CloseServiceHandle(hSCM); + return FALSE; + } + + // make registry entries to support logging messages + // Add the source name as a subkey under the Application + // key in the EventLog service portion of the registry. + StringCbCopyA(szKey, 256, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\IKSD"); + if (RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) { + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return FALSE; + } + + // Add the Event ID message-file name to the 'EventMessageFile' subkey. + RegSetValueEx( hKey, + "EventMessageFile", + 0, + REG_EXPAND_SZ, + (CONST BYTE*)szFilePath, + strlen(szFilePath) + 1); + + // Set the supported types flags. + dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; + RegSetValueEx( hKey, + "TypesSupported", + 0, + REG_DWORD, + (CONST BYTE*)&dwData, + sizeof(DWORD)); + RegCloseKey(hKey); + + // LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, SVCNAME); + + // tidy up + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return TRUE; +} + +BOOL +Uninstall() +{ + BOOL bResult = FALSE; + SC_HANDLE hService; + SC_HANDLE hSCM; + + // Open the Service Control Manager + hSCM = OpenSCManager( NULL, // local machine + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access + if (!hSCM) + return FALSE; + + hService = OpenService( hSCM, + _T(SVCNAME), + DELETE); + if (hService) { + if (DeleteService(hService)) { + // LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, SVCNAME); + bResult = TRUE; + } else { + // LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, SVCNAME); + } + CloseServiceHandle(hService); + } + + CloseServiceHandle(hSCM); + return bResult; +} + + +// Returns TRUE if it found an arg it recognised, FALSE if not +// Note: processing some arguments causes output to stdout to be generated. +BOOL +ParseStandardArgs(int argc, char* argv[]) +{ + char szFilePath[_MAX_PATH]="not a file name"; + + // See if we have any command line args we recognize + if (argc <= 1) + return FALSE; + + if ( _stricmp(argv[1], "-h") == 0 || + _stricmp(argv[1], "-?") == 0 || + _stricmp(argv[1], "/h") == 0 || + _stricmp(argv[1], "/?") == 0) { + + // + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); + fprintf(stderr, "usage: %s [-v | -i | -u | -h]\r\n",szFilePath); + return TRUE; + } else if (_stricmp(argv[1], "-v") == 0 || + _stricmp(argv[1], "/v") == 0 ) { + + // Spit out version info + fprintf(stderr, "%s Version 0.1\n",_T(SVCNAME)); + fprintf(stderr, "The service is %s installed\n", + IsInstalled() ? "currently" : "not"); + return TRUE; // say we processed the argument + + } else if (_stricmp(argv[1], "-i") == 0 || + _stricmp(argv[1], "/i") == 0) { + + // Request to install. + if (IsInstalled()) { + fprintf(stderr, "%s is already installed\n", _T(SVCNAME)); + } else { + // Try and install the copy that's running + if (Install()) { + fprintf(stderr, "%s installed\n", _T(SVCNAME)); + } else { + fprintf(stderr, "%s failed to install. Error %d\n", _T(SVCNAME), GetLastError()); + } + } + return TRUE; // say we processed the argument + + } else if (_stricmp(argv[1], "-u") == 0 || + _stricmp(argv[1], "/u") == 0) { + + // Request to uninstall. + if (!IsInstalled()) { + fprintf(stderr, "%s is not installed\n", _T(SVCNAME)); + } else { + // Try and remove the copy that's installed + if (Uninstall()) { + // Get the executable file path + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); + fprintf(stderr, "%s removed. (You must delete the file (%s) yourself.)\n", + _T(SVCNAME), szFilePath); + } else { + fprintf(stderr, "Could not remove %s. Error %d\n", _T(SVCNAME), GetLastError()); + } + } + return TRUE; // say we processed the argument + + } + + // Don't recognise the args + return FALSE; +} + +int main(int argc, char ** argv) { + + SERVICE_TABLE_ENTRY dispatch_table[] = { + { _T(SVCNAME), (LPSERVICE_MAIN_FUNCTION) service_main }, + { NULL, NULL } + }; + + if ( ParseStandardArgs(argc, argv) ) + return 0; + + if (!StartServiceCtrlDispatcher(dispatch_table)) { + fprintf(stderr, "Can't start service control dispatcher\n"); + } + + return 0; +}