aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey Altman <jaltman@secure-endpoints.com>2006-06-05 04:30:35 +0000
committerJeffrey Altman <jaltman@secure-endpoints.com>2006-06-05 04:30:35 +0000
commit3d6591dd63c23bcc0ae68e94a960c85fd53daad0 (patch)
treeea425b66af681a5f5d5cd63f36af67e7cf0a7384
parent395cb4fe2007693553b37dc53981218e72b3b389 (diff)
downloadkrb5-3d6591dd63c23bcc0ae68e94a960c85fd53daad0.zip
krb5-3d6591dd63c23bcc0ae68e94a960c85fd53daad0.tar.gz
krb5-3d6591dd63c23bcc0ae68e94a960c85fd53daad0.tar.bz2
more updates
git-svn-id: svn://anonsvn.mit.edu/krb5/branches/ccapi@18082 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/lib/ccapi/NTMakefile25
-rw-r--r--src/lib/ccapi/client/NTMakefile13
-rw-r--r--src/lib/ccapi/common/NTMakefile2
-rw-r--r--src/lib/ccapi/doc/implementation-notes.txt156
-rw-r--r--src/lib/ccapi/include/CredentialsCache.h4
-rw-r--r--src/lib/ccapi/include/CredentialsCache2.h22
-rw-r--r--src/lib/ccapi/include/datastore.h (renamed from src/lib/ccapi/server/datastore.h)0
-rw-r--r--src/lib/ccapi/include/rpc_auth.h (renamed from src/lib/ccapi/server/rpc_auth.h)0
-rw-r--r--src/lib/ccapi/server/NTMakefile21
-rw-r--r--src/lib/ccapi/unit-test/NTMakefile56
-rw-r--r--src/lib/ccapi/unit-test/t_ccache.c24
-rw-r--r--src/lib/ccapi/unit-test/t_context.c34
-rw-r--r--src/lib/ccapi/unit-test/t_server.c4
-rw-r--r--src/lib/ccapi/windows/NTMakefile35
-rw-r--r--src/lib/ccapi/windows/cacheapi.def (renamed from src/lib/ccapi/client/cacheapi.def)0
-rw-r--r--src/lib/ccapi/windows/client.c120
-rw-r--r--src/lib/ccapi/windows/dllmain.c (renamed from src/lib/ccapi/client/dllmain.c)0
-rw-r--r--src/lib/ccapi/windows/ntccrpc.acf8
-rw-r--r--src/lib/ccapi/windows/ntccrpc.idl31
-rw-r--r--src/lib/ccapi/windows/server.c638
20 files changed, 1118 insertions, 75 deletions
diff --git a/src/lib/ccapi/NTMakefile b/src/lib/ccapi/NTMakefile
new file mode 100644
index 0000000..57c42e3
--- /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 f9d85b4..2ce87c3 100644
--- a/src/lib/ccapi/client/NTMakefile
+++ b/src/lib/ccapi/client/NTMakefile
@@ -1,6 +1,6 @@
!INCLUDE <WIN32.MAK>
-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 d0d92fc..a43985a 100644
--- a/src/lib/ccapi/common/NTMakefile
+++ b/src/lib/ccapi/common/NTMakefile
@@ -1,6 +1,6 @@
!INCLUDE <WIN32.MAK>
-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 0000000..e6150fb
--- /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 7143da4..12748bb 100644
--- a/src/lib/ccapi/include/CredentialsCache.h
+++ b/src/lib/ccapi/include/CredentialsCache.h
@@ -69,6 +69,10 @@
#include <sys/types.h>
#endif
+#if defined(_WIN32)
+#include <winsock.h>
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
diff --git a/src/lib/ccapi/include/CredentialsCache2.h b/src/lib/ccapi/include/CredentialsCache2.h
index 214d93a..706c869 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
index 4f119f9..4f119f9 100644
--- a/src/lib/ccapi/server/datastore.h
+++ b/src/lib/ccapi/include/datastore.h
diff --git a/src/lib/ccapi/server/rpc_auth.h b/src/lib/ccapi/include/rpc_auth.h
index 010a1e2..010a1e2 100644
--- a/src/lib/ccapi/server/rpc_auth.h
+++ b/src/lib/ccapi/include/rpc_auth.h
diff --git a/src/lib/ccapi/server/NTMakefile b/src/lib/ccapi/server/NTMakefile
index b221bcb..564097c 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 <WIN32.MAK>
-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 eb2fd53..9bb486b 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 <win32.mak>
-!INCLUDE <WIN32.MAK>
+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 6ef33ea..175764e 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 9e35d9a..d76ff78 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 d4d9984..d609394 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 0000000..f6fee6f
--- /dev/null
+++ b/src/lib/ccapi/windows/NTMakefile
@@ -0,0 +1,35 @@
+!include <win32.mak>
+
+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
index c54cc11..c54cc11 100644
--- a/src/lib/ccapi/client/cacheapi.def
+++ b/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 0000000..db0b63a
--- /dev/null
+++ b/src/lib/ccapi/windows/client.c
@@ -0,0 +1,120 @@
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tchar.h>
+#include "ntccrpc.h"
+#include <strsafe.h>
+#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
index 6b4d6bf..6b4d6bf 100644
--- a/src/lib/ccapi/client/dllmain.c
+++ b/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 0000000..77216a9
--- /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 0000000..0dd038f
--- /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 0000000..5ce8e6e
--- /dev/null
+++ b/src/lib/ccapi/windows/server.c
@@ -0,0 +1,638 @@
+
+
+#include <windows.h>
+#include "msg.h"
+#include "marshall.h"
+#include "serv_ops.h"
+#include "datastore.h"
+#include <stdio.h>
+#include <process.h>
+#include <tchar.h>
+#include <rpc.h>
+#include <rpcndr.h>
+#include "ntccrpc.h"
+#include <strsafe.h>
+
+#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;
+}