aboutsummaryrefslogtreecommitdiffstats
path: root/src/ccapi/server
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
committerCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
commit33a9b234e7087f573ef08cd7318c6497ba08b439 (patch)
treed0ea40ad3bf5463a3c55795977c71bcb7d781b4b /src/ccapi/server
downloadsrc-33a9b234e7087f573ef08cd7318c6497ba08b439.tar.gz
src-33a9b234e7087f573ef08cd7318c6497ba08b439.zip
Import MIT KRB5 1.15.1, which will gracefully replace KTH Heimdal.vendor/krb5/1.15.1
The tarball used in this import is the same tarball used in ports/krb5-115 r435378. Obtained from: http://web.mit.edu/kerberos/dist/ Thanks to: pfg (for all your tireless behind-the-scenes effort)
Notes
Notes: svn path=/vendor-crypto/krb5/dist/; revision=320790 svn path=/vendor-crypto/krb5/1.15.1/; revision=320791; tag=vendor/krb5/1.15.1
Diffstat (limited to 'src/ccapi/server')
-rw-r--r--src/ccapi/server/Makefile.in59
-rw-r--r--src/ccapi/server/ccs_array.c309
-rw-r--r--src/ccapi/server/ccs_array.h132
-rw-r--r--src/ccapi/server/ccs_cache_collection.c1109
-rw-r--r--src/ccapi/server/ccs_cache_collection.h72
-rw-r--r--src/ccapi/server/ccs_callback.c238
-rw-r--r--src/ccapi/server/ccs_callback.h61
-rw-r--r--src/ccapi/server/ccs_ccache.c1236
-rw-r--r--src/ccapi/server/ccs_ccache.h82
-rw-r--r--src/ccapi/server/ccs_ccache_iterator.c156
-rw-r--r--src/ccapi/server/ccs_ccache_iterator.h37
-rw-r--r--src/ccapi/server/ccs_client.c236
-rw-r--r--src/ccapi/server/ccs_client.h52
-rw-r--r--src/ccapi/server/ccs_common.h47
-rw-r--r--src/ccapi/server/ccs_credentials.c139
-rw-r--r--src/ccapi/server/ccs_credentials.h46
-rw-r--r--src/ccapi/server/ccs_credentials_iterator.c158
-rw-r--r--src/ccapi/server/ccs_credentials_iterator.h37
-rw-r--r--src/ccapi/server/ccs_list.c361
-rw-r--r--src/ccapi/server/ccs_list.h140
-rw-r--r--src/ccapi/server/ccs_list_internal.c675
-rw-r--r--src/ccapi/server/ccs_list_internal.h94
-rw-r--r--src/ccapi/server/ccs_lock.c248
-rw-r--r--src/ccapi/server/ccs_lock.h61
-rw-r--r--src/ccapi/server/ccs_lock_state.c525
-rw-r--r--src/ccapi/server/ccs_lock_state.h51
-rw-r--r--src/ccapi/server/ccs_os_notify.h37
-rw-r--r--src/ccapi/server/ccs_os_pipe.h42
-rw-r--r--src/ccapi/server/ccs_os_server.h40
-rw-r--r--src/ccapi/server/ccs_pipe.c58
-rw-r--r--src/ccapi/server/ccs_pipe.h42
-rw-r--r--src/ccapi/server/ccs_server.c408
-rw-r--r--src/ccapi/server/ccs_server.h53
-rw-r--r--src/ccapi/server/ccs_types.h120
-rw-r--r--src/ccapi/server/deps170
-rw-r--r--src/ccapi/server/mac/CCacheServerInfo.plist38
-rw-r--r--src/ccapi/server/mac/ccs_os_notify.c79
-rw-r--r--src/ccapi/server/mac/ccs_os_pipe.c79
-rw-r--r--src/ccapi/server/mac/ccs_os_server.c97
-rw-r--r--src/ccapi/server/mac/edu.mit.Kerberos.CCacheServer.plist35
-rw-r--r--src/ccapi/server/unix/Makefile.in12
-rw-r--r--src/ccapi/server/unix/deps1
-rw-r--r--src/ccapi/server/win/Makefile.in114
-rw-r--r--src/ccapi/server/win/Server.sln20
-rw-r--r--src/ccapi/server/win/Server.vcproj227
-rw-r--r--src/ccapi/server/win/WorkItem.cpp142
-rw-r--r--src/ccapi/server/win/WorkQueue.cpp74
-rw-r--r--src/ccapi/server/win/WorkQueue.h51
-rw-r--r--src/ccapi/server/win/ccs_os_pipe.c62
-rw-r--r--src/ccapi/server/win/ccs_os_server.cpp971
-rw-r--r--src/ccapi/server/win/ccs_request_proc.c114
-rw-r--r--src/ccapi/server/win/ccs_win_pipe.c164
-rw-r--r--src/ccapi/server/win/ccs_win_pipe.h68
-rw-r--r--src/ccapi/server/win/workitem.h51
54 files changed, 9730 insertions, 0 deletions
diff --git a/src/ccapi/server/Makefile.in b/src/ccapi/server/Makefile.in
new file mode 100644
index 000000000000..2c01307f523c
--- /dev/null
+++ b/src/ccapi/server/Makefile.in
@@ -0,0 +1,59 @@
+mydir=ccapi$(S)server
+BUILDTOP=$(REL)..$(S)..
+SUBDIRS=unix
+
+LOCALINCLUDES= -I$(srcdir)/../common
+
+STLIBOBJS= \
+ ccs_array.o \
+ ccs_cache_collection.o \
+ ccs_callback.o \
+ ccs_ccache.o \
+ ccs_ccache_iterator.o \
+ ccs_client.o \
+ ccs_credentials.o \
+ ccs_credentials_iterator.o \
+ ccs_list.o \
+ ccs_list_internal.o \
+ ccs_lock.o \
+ ccs_lock_state.o \
+ ccs_pipe.o \
+ ccs_server.o
+
+OBJS= \
+ $(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_pipe.$(OBJEXT) \
+ $(OUTPRE)ccs_server.$(OBJEXT)
+
+SRCS= \
+ ccs_array.c \
+ ccs_cache_collection.c \
+ ccs_callback.c \
+ ccs_ccache.c \
+ ccs_ccache_iterator.c \
+ ccs_client.c \
+ ccs_credentials.c \
+ ccs_credentials_iterator.c \
+ ccs_list.c \
+ ccs_list_internal.c \
+ ccs_lock.c \
+ ccs_lock_state.c \
+ ccs_pipe.c \
+ ccs_server.c
+
+all-unix: all-libobjs
+clean-unix:: clean-libobjs
+
+@libobj_frag@
+
diff --git a/src/ccapi/server/ccs_array.c b/src/ccapi/server/ccs_array.c
new file mode 100644
index 000000000000..7e0874a85aa4
--- /dev/null
+++ b/src/ccapi/server/ccs_array.c
@@ -0,0 +1,309 @@
+/* ccapi/server/ccs_array.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+#include "cci_array_internal.h"
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_client_object_release (cci_array_object_t io_client)
+{
+ return cci_check_error (ccs_client_release ((ccs_client_t) io_client));
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_array_new (ccs_client_array_t *out_array)
+{
+ return cci_array_new (out_array, ccs_client_object_release);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_array_release (ccs_client_array_t io_array)
+{
+ return cci_array_release (io_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint64 ccs_client_array_count (ccs_client_array_t in_array)
+{
+ return cci_array_count (in_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+ccs_client_t ccs_client_array_object_at_index (ccs_client_array_t io_array,
+ cc_uint64 in_position)
+{
+ return (ccs_client_t) cci_array_object_at_index (io_array, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_array_insert (ccs_client_array_t io_array,
+ ccs_client_t in_client,
+ cc_uint64 in_position)
+{
+ return cci_array_insert (io_array, (cci_array_object_t) in_client, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_array_remove (ccs_client_array_t io_array,
+ cc_uint64 in_position)
+{
+ return cci_array_remove (io_array, in_position);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_object_release (cci_array_object_t io_lock)
+{
+ return cci_check_error (ccs_lock_release ((ccs_lock_t) io_lock));
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_array_new (ccs_lock_array_t *out_array)
+{
+ return cci_array_new (out_array, ccs_lock_object_release);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_array_release (ccs_lock_array_t io_array)
+{
+ return cci_array_release (io_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint64 ccs_lock_array_count (ccs_lock_array_t in_array)
+{
+ return cci_array_count (in_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+ccs_lock_t ccs_lock_array_object_at_index (ccs_lock_array_t io_array,
+ cc_uint64 in_position)
+{
+ return (ccs_lock_t) cci_array_object_at_index (io_array, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_array_insert (ccs_lock_array_t io_array,
+ ccs_lock_t in_lock,
+ cc_uint64 in_position)
+{
+ return cci_array_insert (io_array, (cci_array_object_t) in_lock, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_array_remove (ccs_lock_array_t io_array,
+ cc_uint64 in_position)
+{
+ return cci_array_remove (io_array, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+cc_int32 ccs_lock_array_move (ccs_lock_array_t io_array,
+ cc_uint64 in_position,
+ cc_uint64 in_new_position,
+ cc_uint64 *out_real_new_position)
+{
+ return cci_array_move (io_array, in_position, in_new_position, out_real_new_position);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_callback_object_release (cci_array_object_t io_callback)
+{
+ return cci_check_error (ccs_callback_release ((ccs_callback_t) io_callback));
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_array_new (ccs_callback_array_t *out_array)
+{
+ return cci_array_new (out_array, ccs_callback_object_release);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_array_release (ccs_callback_array_t io_array)
+{
+ return cci_array_release (io_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint64 ccs_callback_array_count (ccs_callback_array_t in_array)
+{
+ return cci_array_count (in_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+ccs_callback_t ccs_callback_array_object_at_index (ccs_callback_array_t io_array,
+ cc_uint64 in_position)
+{
+ return (ccs_callback_t) cci_array_object_at_index (io_array, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_array_insert (ccs_callback_array_t io_array,
+ ccs_callback_t in_callback,
+ cc_uint64 in_position)
+{
+ return cci_array_insert (io_array, (cci_array_object_t) in_callback, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_array_remove (ccs_callback_array_t io_array,
+ cc_uint64 in_position)
+{
+ return cci_array_remove (io_array, in_position);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callbackref_array_new (ccs_callbackref_array_t *out_array)
+{
+ /* Ref arrays do not own their contents; pass NULL for release function */
+ return cci_array_new (out_array, NULL);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callbackref_array_release (ccs_callbackref_array_t io_array)
+{
+ return cci_array_release (io_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint64 ccs_callbackref_array_count (ccs_callbackref_array_t in_array)
+{
+ return cci_array_count (in_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+ccs_callback_t ccs_callbackref_array_object_at_index (ccs_callbackref_array_t io_array,
+ cc_uint64 in_position)
+{
+ return (ccs_callback_t) cci_array_object_at_index (io_array, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callbackref_array_insert (ccs_callbackref_array_t io_array,
+ ccs_callback_t in_callback,
+ cc_uint64 in_position)
+{
+ return cci_array_insert (io_array, (cci_array_object_t) in_callback, in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callbackref_array_remove (ccs_callbackref_array_t io_array,
+ cc_uint64 in_position)
+{
+ return cci_array_remove (io_array, in_position);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_iteratorref_array_new (ccs_iteratorref_array_t *out_array)
+{
+ /* Ref arrays do not own their contents; pass NULL for release function */
+ return cci_array_new (out_array, NULL);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_iteratorref_array_release (ccs_iteratorref_array_t io_array)
+{
+ return cci_array_release (io_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint64 ccs_iteratorref_array_count (ccs_iteratorref_array_t in_array)
+{
+ return cci_array_count (in_array);
+}
+
+/* ------------------------------------------------------------------------ */
+
+ccs_generic_list_iterator_t ccs_iteratorref_array_object_at_index (ccs_iteratorref_array_t io_array,
+ cc_uint64 in_position)
+{
+ return (ccs_generic_list_iterator_t) cci_array_object_at_index (io_array,
+ in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_iteratorref_array_insert (ccs_iteratorref_array_t io_array,
+ ccs_generic_list_iterator_t in_iterator,
+ cc_uint64 in_position)
+{
+ return cci_array_insert (io_array,
+ (cci_array_object_t) in_iterator,
+ in_position);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_iteratorref_array_remove (ccs_iteratorref_array_t io_array,
+ cc_uint64 in_position)
+{
+ return cci_array_remove (io_array, in_position);
+}
diff --git a/src/ccapi/server/ccs_array.h b/src/ccapi/server/ccs_array.h
new file mode 100644
index 000000000000..470812b3dcfe
--- /dev/null
+++ b/src/ccapi/server/ccs_array.h
@@ -0,0 +1,132 @@
+/* ccapi/server/ccs_array.h */
+/*
+ * Copyright 2006, 2007 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.
+ */
+
+#ifndef CCS_ARRAY_H
+#define CCS_ARRAY_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_client_array_new (ccs_client_array_t *out_array);
+
+cc_int32 ccs_client_array_release (ccs_client_array_t io_array);
+
+cc_uint64 ccs_client_array_count (ccs_client_array_t in_array);
+
+ccs_client_t ccs_client_array_object_at_index (ccs_client_array_t io_array,
+ cc_uint64 in_position);
+
+cc_int32 ccs_client_array_insert (ccs_client_array_t io_array,
+ ccs_client_t in_client,
+ cc_uint64 in_position);
+
+cc_int32 ccs_client_array_remove (ccs_client_array_t io_array,
+ cc_uint64 in_position);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_lock_array_new (ccs_lock_array_t *out_array);
+
+cc_int32 ccs_lock_array_release (ccs_lock_array_t io_array);
+
+cc_uint64 ccs_lock_array_count (ccs_lock_array_t in_array);
+
+ccs_lock_t ccs_lock_array_object_at_index (ccs_lock_array_t io_array,
+ cc_uint64 in_position);
+
+cc_int32 ccs_lock_array_insert (ccs_lock_array_t io_array,
+ ccs_lock_t in_lock,
+ cc_uint64 in_position);
+
+cc_int32 ccs_lock_array_remove (ccs_lock_array_t io_array,
+ cc_uint64 in_position);
+
+cc_int32 ccs_lock_array_move (ccs_lock_array_t io_array,
+ cc_uint64 in_position,
+ cc_uint64 in_new_position,
+ cc_uint64 *out_real_new_position);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_callback_array_new (ccs_callback_array_t *out_array);
+
+cc_int32 ccs_callback_array_release (ccs_callback_array_t io_array);
+
+cc_uint64 ccs_callback_array_count (ccs_callback_array_t in_array);
+
+ccs_callback_t ccs_callback_array_object_at_index (ccs_callback_array_t io_array,
+ cc_uint64 in_position);
+
+cc_int32 ccs_callback_array_insert (ccs_callback_array_t io_array,
+ ccs_callback_t in_callback,
+ cc_uint64 in_position);
+
+cc_int32 ccs_callback_array_remove (ccs_callback_array_t io_array,
+ cc_uint64 in_position);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_callbackref_array_new (ccs_callbackref_array_t *out_array);
+
+cc_int32 ccs_callbackref_array_release (ccs_callbackref_array_t io_array);
+
+cc_uint64 ccs_callbackref_array_count (ccs_callbackref_array_t in_array);
+
+ccs_callback_t ccs_callbackref_array_object_at_index (ccs_callbackref_array_t io_array,
+ cc_uint64 in_position);
+
+cc_int32 ccs_callbackref_array_insert (ccs_callbackref_array_t io_array,
+ ccs_callback_t in_callback,
+ cc_uint64 in_position);
+
+cc_int32 ccs_callbackref_array_remove (ccs_callbackref_array_t io_array,
+ cc_uint64 in_position);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_iteratorref_array_new (ccs_iteratorref_array_t *out_array);
+
+cc_int32 ccs_iteratorref_array_release (ccs_iteratorref_array_t io_array);
+
+cc_uint64 ccs_iteratorref_array_count (ccs_iteratorref_array_t in_array);
+
+ccs_generic_list_iterator_t ccs_iteratorref_array_object_at_index (ccs_iteratorref_array_t io_array,
+ cc_uint64 in_position);
+
+cc_int32 ccs_iteratorref_array_insert (ccs_iteratorref_array_t io_array,
+ ccs_generic_list_iterator_t in_iterator,
+ cc_uint64 in_position);
+
+cc_int32 ccs_iteratorref_array_remove (ccs_iteratorref_array_t io_array,
+ cc_uint64 in_position);
+
+#endif /* CCS_ARRAY_H */
diff --git a/src/ccapi/server/ccs_cache_collection.c b/src/ccapi/server/ccs_cache_collection.c
new file mode 100644
index 000000000000..333007352c5f
--- /dev/null
+++ b/src/ccapi/server/ccs_cache_collection.c
@@ -0,0 +1,1109 @@
+/* ccapi/server/ccs_cache_collection.c */
+/*
+ * Copyright 2006, 2007 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 "k5-platform.h" /* pull in asprintf decl/defn */
+#include "ccs_common.h"
+#include "ccs_os_notify.h"
+
+struct ccs_cache_collection_d {
+ cc_time_t last_changed_time;
+ cc_uint64 next_unique_name;
+ cci_identifier_t identifier;
+ ccs_lock_state_t lock_state;
+ ccs_ccache_list_t ccaches;
+ ccs_callback_array_t change_callbacks;
+};
+
+struct ccs_cache_collection_d ccs_cache_collection_initializer = { 0, 0, NULL, NULL, NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_new (ccs_cache_collection_t *out_cache_collection)
+{
+ cc_int32 err = ccNoError;
+ ccs_cache_collection_t cache_collection = NULL;
+
+ if (!out_cache_collection) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cache_collection = malloc (sizeof (*cache_collection));
+ if (cache_collection) {
+ *cache_collection = ccs_cache_collection_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = ccs_server_new_identifier (&cache_collection->identifier);
+ }
+
+ if (!err) {
+ err = ccs_lock_state_new (&cache_collection->lock_state,
+ ccErrInvalidContext,
+ ccErrContextLocked,
+ ccErrContextUnlocked);
+ }
+
+ if (!err) {
+ err = ccs_ccache_list_new (&cache_collection->ccaches);
+ }
+
+ if (!err) {
+ err = ccs_callback_array_new (&cache_collection->change_callbacks);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_changed (cache_collection);
+ }
+
+ if (!err) {
+ *out_cache_collection = cache_collection;
+ cache_collection = NULL;
+ }
+
+ ccs_cache_collection_release (cache_collection);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_release (ccs_cache_collection_t io_cache_collection)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_cache_collection) {
+ cci_identifier_release (io_cache_collection->identifier);
+ ccs_lock_state_release (io_cache_collection->lock_state);
+ ccs_ccache_list_release (io_cache_collection->ccaches);
+ ccs_callback_array_release (io_cache_collection->change_callbacks);
+ free (io_cache_collection);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_compare_identifier (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_equal ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_compare (in_cache_collection->identifier,
+ in_identifier,
+ out_equal);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_changed (ccs_cache_collection_t io_cache_collection)
+{
+ cc_int32 err = ccNoError;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_time_t now = time (NULL);
+
+ if (io_cache_collection->last_changed_time < now) {
+ io_cache_collection->last_changed_time = now;
+ } else {
+ io_cache_collection->last_changed_time++;
+ }
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_new (&reply_data);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_time (reply_data, io_cache_collection->last_changed_time);
+ }
+
+ if (!err) {
+ /* Loop over callbacks sending messages to them */
+ cc_uint64 i;
+ cc_uint64 count = ccs_callback_array_count (io_cache_collection->change_callbacks);
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_callback_t callback = ccs_callback_array_object_at_index (io_cache_collection->change_callbacks, i);
+
+ err = ccs_callback_reply_to_client (callback, reply_data);
+
+ if (!err) {
+ cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
+ err = ccs_callback_array_remove (io_cache_collection->change_callbacks, i);
+ break;
+ }
+ }
+ }
+
+ if (!err) {
+ err = ccs_os_notify_cache_collection_changed (io_cache_collection);
+ }
+
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_invalidate_change_callback (ccs_callback_owner_t io_cache_collection,
+ ccs_callback_t in_callback)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_callback ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ /* Remove callback */
+ ccs_cache_collection_t cache_collection = (ccs_cache_collection_t) io_cache_collection;
+ cc_uint64 i;
+ cc_uint64 count = ccs_callback_array_count (cache_collection->change_callbacks);
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_callback_t callback = ccs_callback_array_object_at_index (cache_collection->change_callbacks, i);
+
+ if (callback == in_callback) {
+ cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
+ err = ccs_callback_array_remove (cache_collection->change_callbacks, i);
+ break;
+ }
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_find_ccache_by_name (ccs_cache_collection_t in_cache_collection,
+ const char *in_name,
+ ccs_ccache_t *out_ccache)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_list_iterator_t iterator = NULL;
+
+ if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_name ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_new_iterator (in_cache_collection->ccaches,
+ CCS_PIPE_NULL,
+ &iterator);
+ }
+
+ while (!err) {
+ ccs_ccache_t ccache = NULL;
+
+ err = ccs_ccache_list_iterator_next (iterator, &ccache);
+
+ if (!err) {
+ cc_uint32 equal = 0;
+
+ err = ccs_ccache_compare_name (ccache, in_name, &equal);
+
+ if (!err && equal) {
+ *out_ccache = ccache;
+ break;
+ }
+ }
+ }
+ if (err == ccIteratorEnd) { err = ccErrCCacheNotFound; }
+
+ if (iterator) { ccs_ccache_list_iterator_release (iterator); }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_find_ccache (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ ccs_ccache_t *out_ccache)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_find (in_cache_collection->ccaches,
+ in_identifier, out_ccache);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_collection_move_ccache (ccs_cache_collection_t io_cache_collection,
+ cci_identifier_t in_source_identifier,
+ ccs_ccache_t io_destination_ccache)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_t source_ccache = NULL;
+
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_source_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_destination_ccache) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_find_ccache (io_cache_collection,
+ in_source_identifier,
+ &source_ccache);
+ }
+
+ if (!err) {
+ err = ccs_ccache_swap_contents (source_ccache,
+ io_destination_ccache,
+ io_cache_collection);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_destroy_ccache (io_cache_collection,
+ in_source_identifier);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_destroy_ccache (ccs_cache_collection_t io_cache_collection,
+ cci_identifier_t in_identifier)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_find_ccache (io_cache_collection,
+ in_identifier,
+ &ccache);
+ }
+
+ if (!err) {
+ /* Notify before deletion because after deletion the ccache
+ * will no longer exist (and won't know about its clients) */
+ err = ccs_ccache_changed (ccache, io_cache_collection);
+ }
+
+ if (!err) {
+ err = ccs_ccache_list_remove (io_cache_collection->ccaches,
+ in_identifier);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_find_ccache_iterator (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ ccs_ccache_iterator_t *out_ccache_iterator)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_ccache_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_find_iterator (in_cache_collection->ccaches,
+ in_identifier,
+ out_ccache_iterator);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_find_credentials_iterator (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ ccs_ccache_t *out_ccache,
+ ccs_credentials_iterator_t *out_credentials_iterator)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_list_iterator_t iterator = NULL;
+
+ if (!in_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_credentials_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_new_iterator (in_cache_collection->ccaches,
+ CCS_PIPE_NULL,
+ &iterator);
+ }
+
+ while (!err) {
+ ccs_ccache_t ccache = NULL;
+
+ err = ccs_ccache_list_iterator_next (iterator, &ccache);
+
+ if (!err) {
+ cc_int32 terr = ccs_ccache_find_credentials_iterator (ccache,
+ in_identifier,
+ out_credentials_iterator);
+ if (!terr) {
+ *out_ccache = ccache;
+ break;
+ }
+ }
+ }
+ if (err == ccIteratorEnd) { err = cci_check_error (ccErrInvalidCredentialsIterator); }
+
+ if (iterator) { ccs_ccache_list_iterator_release (iterator); }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_get_next_unique_ccache_name (ccs_cache_collection_t io_cache_collection,
+ char **out_name)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 count = 0;
+ char *name = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!out_name ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_list_count (io_cache_collection->ccaches, &count);
+ }
+
+ if (!err) {
+ if (count > 0) {
+ while (!err) {
+ int ret = asprintf (&name, "%lld", io_cache_collection->next_unique_name++);
+ if (ret < 0 || !name) { err = cci_check_error (ccErrNoMem); }
+
+ if (!err) {
+ ccs_ccache_t ccache = NULL; /* temporary to hold ccache pointer */
+ err = ccs_cache_collection_find_ccache_by_name (io_cache_collection,
+ name, &ccache);
+ }
+
+ if (err == ccErrCCacheNotFound) {
+ err = ccNoError;
+ break; /* found a unique one */
+ }
+ }
+ } else {
+ name = strdup (k_cci_context_initial_ccache_name);
+ if (!name) { err = cci_check_error (ccErrNoMem); }
+ }
+ }
+
+ if (!err) {
+ *out_name = name;
+ name = NULL;
+ }
+
+ free (name);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_get_default_ccache (ccs_cache_collection_t in_cache_collection,
+ ccs_ccache_t *out_ccache)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 count = 0;
+
+ if (!in_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_count (in_cache_collection->ccaches, &count);
+ }
+
+ if (!err) {
+ if (count > 0) {
+ /* First ccache is the default */
+ ccs_ccache_list_iterator_t iterator = NULL;
+
+ err = ccs_ccache_list_new_iterator (in_cache_collection->ccaches,
+ CCS_PIPE_NULL,
+ &iterator);
+
+ if (!err) {
+ err = ccs_ccache_list_iterator_next (iterator, out_ccache);
+ }
+
+ ccs_ccache_list_iterator_release (iterator);
+
+ } else {
+ err = cci_check_error (ccErrCCacheNotFound);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_set_default_ccache (ccs_cache_collection_t io_cache_collection,
+ cci_identifier_t in_identifier)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_t old_default = NULL;
+ ccs_ccache_t new_default = NULL;
+ cc_uint32 equal = 0;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_get_default_ccache (io_cache_collection,
+ &old_default);
+ }
+
+ if (!err) {
+ err = ccs_ccache_compare_identifier (old_default, in_identifier, &equal);
+ }
+
+
+ if (!err && !equal) {
+ err = ccs_ccache_list_push_front (io_cache_collection->ccaches,
+ in_identifier);
+
+ if (!err) {
+ err = ccs_ccache_notify_default_state_changed (old_default,
+ io_cache_collection,
+ 0 /* no longer default */);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_get_default_ccache (io_cache_collection,
+ &new_default);
+ }
+
+ if (!err) {
+ err = ccs_ccache_notify_default_state_changed (new_default,
+ io_cache_collection,
+ 1 /* now default */);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_changed (io_cache_collection);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#pragma mark -- IPC Messages --
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_sync (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_write (io_cache_collection->identifier, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_get_change_time (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_cache_collection->last_changed_time);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_wait_for_change (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data,
+ cc_uint32 *out_will_block)
+{
+ cc_int32 err = ccNoError;
+ cc_time_t last_wait_for_change_time = 0;
+ cc_uint32 will_block = 0;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe )) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_time (in_request_data, &last_wait_for_change_time);
+ }
+
+ if (!err) {
+ if (last_wait_for_change_time < io_cache_collection->last_changed_time) {
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_cache_collection->last_changed_time);
+
+ } else {
+ ccs_callback_t callback = NULL;
+
+ err = ccs_callback_new (&callback,
+ ccErrInvalidContext,
+ in_client_pipe,
+ in_reply_pipe,
+ (ccs_callback_owner_t) io_cache_collection,
+ ccs_cache_collection_invalidate_change_callback);
+
+ if (!err) {
+ err = ccs_callback_array_insert (io_cache_collection->change_callbacks, callback,
+ ccs_callback_array_count (io_cache_collection->change_callbacks));
+ if (!err) { callback = NULL; /* take ownership */ }
+
+ will_block = 1;
+ }
+
+ ccs_callback_release (callback);
+ }
+ }
+
+ if (!err) {
+ *out_will_block = will_block;
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_get_default_ccache_name (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 count = 0;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_list_count (io_cache_collection->ccaches, &count);
+ }
+
+ if (!err) {
+ if (count > 0) {
+ ccs_ccache_t ccache = NULL;
+
+ err = ccs_cache_collection_get_default_ccache (io_cache_collection, &ccache);
+
+ if (!err) {
+ err = ccs_ccache_write_name (ccache, io_reply_data);
+ }
+ } else {
+ err = krb5int_ipc_stream_write_string (io_reply_data,
+ k_cci_context_initial_ccache_name);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_open_ccache (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ char *name = NULL;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_string (in_request_data, &name);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_find_ccache_by_name (io_cache_collection,
+ name, &ccache);
+ }
+
+ if (!err) {
+ err = ccs_ccache_write (ccache, io_reply_data);
+ }
+
+ krb5int_ipc_stream_free_string (name);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_open_default_ccache (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_get_default_ccache (io_cache_collection,
+ &ccache);
+ }
+
+ if (!err) {
+ err = ccs_ccache_write (ccache, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_create_ccache (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ char *name = NULL;
+ cc_uint32 cred_vers;
+ char *principal = NULL;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_string (in_request_data, &name);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_string (in_request_data, &principal);
+ }
+
+ if (!err) {
+ cc_int32 terr = ccs_cache_collection_find_ccache_by_name (io_cache_collection,
+ name,
+ &ccache);
+
+ if (!terr) {
+ err = ccs_ccache_reset (ccache, io_cache_collection, cred_vers, principal);
+
+ } else {
+ err = ccs_ccache_new (&ccache, cred_vers, name, principal,
+ io_cache_collection->ccaches);
+ }
+ }
+
+ if (!err) {
+ err = ccs_ccache_write (ccache, io_reply_data);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_changed (io_cache_collection);
+ }
+
+ krb5int_ipc_stream_free_string (name);
+ krb5int_ipc_stream_free_string (principal);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_create_default_ccache (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 cred_vers;
+ char *principal = NULL;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_string (in_request_data, &principal);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_get_default_ccache (io_cache_collection,
+ &ccache);
+
+ if (!err) {
+ err = ccs_ccache_reset (ccache, io_cache_collection, cred_vers, principal);
+
+ } else if (err == ccErrCCacheNotFound) {
+ char *name = NULL;
+
+ err = ccs_cache_collection_get_next_unique_ccache_name (io_cache_collection,
+ &name);
+
+ if (!err) {
+ err = ccs_ccache_new (&ccache, cred_vers, name, principal,
+ io_cache_collection->ccaches);
+ }
+
+ free (name);
+ }
+ }
+
+ if (!err) {
+ err = ccs_ccache_write (ccache, io_reply_data);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_changed (io_cache_collection);
+ }
+
+ krb5int_ipc_stream_free_string (principal);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_create_new_ccache (ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 cred_vers;
+ char *principal = NULL;
+ char *name = NULL;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_string (in_request_data, &principal);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_get_next_unique_ccache_name (io_cache_collection,
+ &name);
+ }
+
+ if (!err) {
+ err = ccs_ccache_new (&ccache, cred_vers, name, principal,
+ io_cache_collection->ccaches);
+ }
+
+ if (!err) {
+ err = ccs_ccache_write (ccache, io_reply_data);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_changed (io_cache_collection);
+ }
+
+ free (name);
+ krb5int_ipc_stream_free_string (principal);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_new_ccache_iterator (ccs_cache_collection_t io_cache_collection,
+ ccs_pipe_t in_client_pipe,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_iterator_t ccache_iterator = NULL;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_new_iterator (io_cache_collection->ccaches,
+ in_client_pipe,
+ &ccache_iterator);
+ }
+
+ if (!err) {
+ err = ccs_ccache_list_iterator_write (ccache_iterator, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_lock (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 lock_type;
+ cc_uint32 block;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &lock_type);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &block);
+ }
+
+ if (!err) {
+ err = ccs_lock_state_add (io_cache_collection->lock_state,
+ in_client_pipe, in_reply_pipe,
+ lock_type, block, out_will_block);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_unlock (ccs_pipe_t in_client_pipe,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_lock_state_remove (io_cache_collection->lock_state,
+ in_client_pipe);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+ cc_int32 ccs_cache_collection_handle_message (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_cache_collection_t io_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream *out_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 will_block = 0;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_new (&reply_data);
+ }
+
+ if (!err) {
+ if (in_request_name == cci_context_unused_release_msg_id) {
+ /* Old release message. Do nothing. */
+
+ } else if (in_request_name == cci_context_sync_msg_id) {
+ err = ccs_cache_collection_sync (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_get_change_time_msg_id) {
+ err = ccs_cache_collection_get_change_time (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_wait_for_change_msg_id) {
+ err = ccs_cache_collection_wait_for_change (in_client_pipe, in_reply_pipe,
+ io_cache_collection,
+ in_request_data, reply_data,
+ &will_block);
+
+ } else if (in_request_name == cci_context_get_default_ccache_name_msg_id) {
+ err = ccs_cache_collection_get_default_ccache_name (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_open_ccache_msg_id) {
+ err = ccs_cache_collection_open_ccache (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_open_default_ccache_msg_id) {
+ err = ccs_cache_collection_open_default_ccache (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_create_ccache_msg_id) {
+ err = ccs_cache_collection_create_ccache (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_create_default_ccache_msg_id) {
+ err = ccs_cache_collection_create_default_ccache (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_create_new_ccache_msg_id) {
+ err = ccs_cache_collection_create_new_ccache (io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_context_new_ccache_iterator_msg_id) {
+ err = ccs_cache_collection_new_ccache_iterator (io_cache_collection,
+ in_client_pipe,
+ in_request_data,
+ reply_data);
+
+ } else if (in_request_name == cci_context_lock_msg_id) {
+ err = ccs_cache_collection_lock (in_client_pipe, in_reply_pipe,
+ io_cache_collection,
+ in_request_data,
+ &will_block, reply_data);
+
+ } else if (in_request_name == cci_context_unlock_msg_id) {
+ err = ccs_cache_collection_unlock (in_client_pipe, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else {
+ err = ccErrBadInternalMessage;
+ }
+ }
+
+ if (!err) {
+ *out_will_block = will_block;
+ if (!will_block) {
+ *out_reply_data = reply_data;
+ reply_data = NULL; /* take ownership */
+ } else {
+ *out_reply_data = NULL;
+ }
+ }
+
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_cache_collection.h b/src/ccapi/server/ccs_cache_collection.h
new file mode 100644
index 000000000000..37f7633a38be
--- /dev/null
+++ b/src/ccapi/server/ccs_cache_collection.h
@@ -0,0 +1,72 @@
+/* ccapi/server/ccs_cache_collection.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CACHE_COLLECTION_H
+#define CCS_CACHE_COLLECTION_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_cache_collection_new (ccs_cache_collection_t *out_cache_collection);
+
+cc_int32 ccs_cache_collection_release (ccs_cache_collection_t io_cache_collection);
+
+cc_int32 ccs_cache_collection_compare_identifier (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal);
+
+cc_int32 ccs_cache_collection_changed (ccs_cache_collection_t io_cache_collection);
+
+cc_int32 ccs_cache_collection_set_default_ccache (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_cache_collection_find_ccache (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ ccs_ccache_t *out_ccache);
+
+cc_int32 ccs_ccache_collection_move_ccache (ccs_cache_collection_t io_cache_collection,
+ cci_identifier_t in_source_identifier,
+ ccs_ccache_t io_destination_ccache);
+
+cc_int32 ccs_cache_collection_destroy_ccache (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_cache_collection_find_ccache_iterator (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ ccs_ccache_iterator_t *out_ccache_iterator);
+
+cc_int32 ccs_cache_collection_find_credentials_iterator (ccs_cache_collection_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ ccs_ccache_t *out_ccache,
+ ccs_credentials_iterator_t *out_credentials_iterator);
+
+cc_int32 ccs_cache_collection_handle_message (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_cache_collection_t io_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream *out_reply_data);
+
+#endif /* CCS_CACHE_COLLECTION_H */
diff --git a/src/ccapi/server/ccs_callback.c b/src/ccapi/server/ccs_callback.c
new file mode 100644
index 000000000000..d758acb1528f
--- /dev/null
+++ b/src/ccapi/server/ccs_callback.c
@@ -0,0 +1,238 @@
+/* ccapi/server/ccs_callback.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+
+struct ccs_callback_d {
+ cc_int32 pending;
+ cc_int32 invalid_object_err;
+ ccs_pipe_t client_pipe;
+ ccs_pipe_t reply_pipe;
+ ccs_callback_owner_t owner; /* pointer to owner */
+ ccs_callback_owner_invalidate_t owner_invalidate;
+};
+
+struct ccs_callback_d ccs_callback_initializer = { 1, 1, CCS_PIPE_NULL, CCS_PIPE_NULL, NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_new (ccs_callback_t *out_callback,
+ cc_int32 in_invalid_object_err,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_callback_owner_t in_owner,
+ ccs_callback_owner_invalidate_t in_owner_invalidate_function)
+{
+ cc_int32 err = ccNoError;
+ ccs_callback_t callback = NULL;
+ ccs_client_t client = NULL;
+
+ if (!out_callback ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_owner ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_owner_invalidate_function ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ callback = malloc (sizeof (*callback));
+ if (callback) {
+ *callback = ccs_callback_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = ccs_server_client_for_pipe (in_client_pipe, &client);
+ }
+
+ if (!err) {
+ err = ccs_pipe_copy (&callback->client_pipe, in_client_pipe);
+ }
+
+ if (!err) {
+ err = ccs_pipe_copy (&callback->reply_pipe, in_reply_pipe);
+ }
+
+ if (!err) {
+ callback->client_pipe = in_client_pipe;
+ callback->reply_pipe = in_reply_pipe;
+ callback->invalid_object_err = in_invalid_object_err;
+ callback->owner = in_owner;
+ callback->owner_invalidate = in_owner_invalidate_function;
+
+ err = ccs_client_add_callback (client, callback);
+ }
+
+ if (!err) {
+ *out_callback = callback;
+ callback = NULL;
+ }
+
+ ccs_callback_release (callback);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_release (ccs_callback_t io_callback)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_callback) {
+ ccs_client_t client = NULL;
+
+ if (io_callback->pending) {
+ err = ccs_server_send_reply (io_callback->reply_pipe,
+ io_callback->invalid_object_err, NULL);
+
+ io_callback->pending = 0;
+ }
+
+ if (!err) {
+ err = ccs_server_client_for_pipe (io_callback->client_pipe, &client);
+ }
+
+ if (!err && client) {
+ /* if client object still has a reference to us, remove it */
+ err = ccs_client_remove_callback (client, io_callback);
+ }
+
+ if (!err) {
+ ccs_pipe_release (io_callback->client_pipe);
+ ccs_pipe_release (io_callback->reply_pipe);
+ free (io_callback);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_invalidate (ccs_callback_t io_callback)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_callback) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ io_callback->pending = 0; /* client is dead, don't try to talk to it */
+ if (io_callback->owner_invalidate) {
+ err = io_callback->owner_invalidate (io_callback->owner, io_callback);
+ } else {
+ cci_debug_printf ("WARNING %s() unable to notify callback owner!",
+ __FUNCTION__);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_reply_to_client (ccs_callback_t io_callback,
+ k5_ipc_stream in_stream)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_callback) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ if (io_callback->pending) {
+ cci_debug_printf ("%s: callback %p replying to client.", __FUNCTION__, io_callback);
+
+ err = ccs_server_send_reply (io_callback->reply_pipe, err, in_stream);
+
+ if (err) {
+ cci_debug_printf ("WARNING %s() called on a lock belonging to a dead client!",
+ __FUNCTION__);
+ }
+
+ io_callback->pending = 0;
+ } else {
+ cci_debug_printf ("WARNING %s() called on non-pending callback!",
+ __FUNCTION__);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint32 ccs_callback_is_pending (ccs_callback_t in_callback,
+ cc_uint32 *out_pending)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_callback) { err = cci_check_error (ccErrBadParam); }
+ if (!out_pending) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_pending = in_callback->pending;
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_is_for_client_pipe (ccs_callback_t in_callback,
+ ccs_pipe_t in_client_pipe,
+ cc_uint32 *out_is_for_client_pipe)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_callback ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!out_is_for_client_pipe ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_pipe_compare (in_callback->client_pipe, in_client_pipe,
+ out_is_for_client_pipe);
+ }
+
+ return cci_check_error (err);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_callback_client_pipe (ccs_callback_t in_callback,
+ ccs_pipe_t *out_client_pipe)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_callback ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_client_pipe) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_client_pipe = in_callback->client_pipe;
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_callback.h b/src/ccapi/server/ccs_callback.h
new file mode 100644
index 000000000000..30c2228010a7
--- /dev/null
+++ b/src/ccapi/server/ccs_callback.h
@@ -0,0 +1,61 @@
+/* ccapi/server/ccs_callback.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CALLBACK_H
+#define CCS_CALLBACK_H
+
+#include "ccs_types.h"
+
+struct ccs_callback_owner_d;
+typedef struct ccs_callback_owner_d *ccs_callback_owner_t;
+
+typedef cc_int32 (*ccs_callback_owner_invalidate_t) (ccs_callback_owner_t, ccs_callback_t);
+
+
+cc_int32 ccs_callback_new (ccs_callback_t *out_callback,
+ cc_int32 in_invalid_object_err,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_callback_owner_t in_owner,
+ ccs_callback_owner_invalidate_t in_owner_invalidate_function);
+
+cc_int32 ccs_callback_release (ccs_callback_t io_callback);
+
+cc_int32 ccs_callback_invalidate (ccs_callback_t io_callback);
+
+cc_int32 ccs_callback_reply_to_client (ccs_callback_t io_callback,
+ k5_ipc_stream in_stream);
+
+cc_uint32 ccs_callback_is_pending (ccs_callback_t in_callback,
+ cc_uint32 *out_pending);
+
+cc_int32 ccs_callback_is_for_client_pipe (ccs_callback_t in_callback,
+ ccs_pipe_t in_client_pipe,
+ cc_uint32 *out_is_for_client_pipe);
+
+cc_int32 ccs_callback_client_pipe (ccs_callback_t in_callback,
+ ccs_pipe_t *out_client_pipe);
+
+#endif /* CCS_CALLBACK_H */
diff --git a/src/ccapi/server/ccs_ccache.c b/src/ccapi/server/ccs_ccache.c
new file mode 100644
index 000000000000..65c59e4be8e6
--- /dev/null
+++ b/src/ccapi/server/ccs_ccache.c
@@ -0,0 +1,1236 @@
+/* ccapi/server/ccs_ccache.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+#include "ccs_os_notify.h"
+
+struct ccs_ccache_d {
+ cci_identifier_t identifier;
+ ccs_lock_state_t lock_state;
+ cc_uint32 creds_version;
+ char *name;
+ char *v4_principal;
+ char *v5_principal;
+ cc_time_t last_default_time;
+ cc_time_t last_changed_time;
+ cc_uint32 kdc_time_offset_v4_valid;
+ cc_time_t kdc_time_offset_v4;
+ cc_uint32 kdc_time_offset_v5_valid;
+ cc_time_t kdc_time_offset_v5;
+ ccs_credentials_list_t credentials;
+ ccs_callback_array_t change_callbacks;
+};
+
+struct ccs_ccache_d ccs_ccache_initializer = { NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_new (ccs_ccache_t *out_ccache,
+ cc_uint32 in_creds_version,
+ const char *in_name,
+ const char *in_principal,
+ ccs_ccache_list_t io_ccache_list)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_t ccache = NULL;
+
+ if (!out_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_name ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_principal) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ ccache = malloc (sizeof (*ccache));
+ if (ccache) {
+ *ccache = ccs_ccache_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = ccs_server_new_identifier (&ccache->identifier);
+ }
+
+ if (!err) {
+ err = ccs_lock_state_new (&ccache->lock_state,
+ ccErrInvalidCCache,
+ ccErrCCacheLocked,
+ ccErrCCacheUnlocked);
+ }
+
+ if (!err) {
+ ccache->name = strdup (in_name);
+ if (!ccache->name) { err = cci_check_error (ccErrNoMem); }
+ }
+
+ if (!err) {
+ ccache->creds_version = in_creds_version;
+
+ if (ccache->creds_version == cc_credentials_v4) {
+ ccache->v4_principal = strdup (in_principal);
+ if (!ccache->v4_principal) { err = cci_check_error (ccErrNoMem); }
+
+ } else if (ccache->creds_version == cc_credentials_v5) {
+ ccache->v5_principal = strdup (in_principal);
+ if (!ccache->v5_principal) { err = cci_check_error (ccErrNoMem); }
+
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ if (!err) {
+ err = ccs_credentials_list_new (&ccache->credentials);
+ }
+
+ if (!err) {
+ err = ccs_callback_array_new (&ccache->change_callbacks);
+ }
+
+ if (!err) {
+ cc_uint64 now = time (NULL);
+ cc_uint64 count = 0;
+
+ err = ccs_ccache_list_count (io_ccache_list, &count);
+
+ if (!err) {
+ /* first cache is default */
+ ccache->last_default_time = (count == 0) ? now : 0;
+ cci_debug_printf ("%s ccache->last_default_time is %d.",
+ __FUNCTION__, ccache->last_default_time);
+ ccache->last_changed_time = now;
+ }
+ }
+
+ if (!err) {
+ /* Add self to the list of ccaches */
+ err = ccs_ccache_list_add (io_ccache_list, ccache);
+ }
+
+ if (!err) {
+ *out_ccache = ccache;
+ ccache = NULL;
+ }
+
+ ccs_ccache_release (ccache);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_reset (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ cc_uint32 in_creds_version,
+ const char *in_principal)
+{
+ cc_int32 err = ccNoError;
+ char *v4_principal = NULL;
+ char *v5_principal = NULL;
+ ccs_credentials_list_t credentials = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_principal ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ io_ccache->creds_version = in_creds_version;
+
+ if (io_ccache->creds_version == cc_credentials_v4) {
+ v4_principal = strdup (in_principal);
+ if (!v4_principal) { err = cci_check_error (ccErrNoMem); }
+
+ } else if (io_ccache->creds_version == cc_credentials_v5) {
+ v5_principal = strdup (in_principal);
+ if (!v5_principal) { err = cci_check_error (ccErrNoMem); }
+
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ if (!err) {
+ err = ccs_credentials_list_new (&credentials);
+ }
+
+ if (!err) {
+ io_ccache->kdc_time_offset_v4 = 0;
+ io_ccache->kdc_time_offset_v4_valid = 0;
+ io_ccache->kdc_time_offset_v5 = 0;
+ io_ccache->kdc_time_offset_v5_valid = 0;
+
+ if (io_ccache->v4_principal) { free (io_ccache->v4_principal); }
+ io_ccache->v4_principal = v4_principal;
+ v4_principal = NULL; /* take ownership */
+
+ if (io_ccache->v5_principal) { free (io_ccache->v5_principal); }
+ io_ccache->v5_principal = v5_principal;
+ v5_principal = NULL; /* take ownership */
+
+ ccs_credentials_list_release (io_ccache->credentials);
+ io_ccache->credentials = credentials;
+ credentials = NULL; /* take ownership */
+
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ free (v4_principal);
+ free (v5_principal);
+ ccs_credentials_list_release (credentials);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_swap_contents (ccs_ccache_t io_source_ccache,
+ ccs_ccache_t io_destination_ccache,
+ ccs_cache_collection_t io_cache_collection)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_source_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_destination_ccache) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ struct ccs_ccache_d temp_ccache = *io_destination_ccache;
+
+ /* swap everything */
+ *io_destination_ccache = *io_source_ccache;
+ *io_source_ccache = temp_ccache;
+
+ /* swap back the name and identifier */
+ io_source_ccache->identifier = io_destination_ccache->identifier;
+ io_destination_ccache->identifier = temp_ccache.identifier;
+
+ io_source_ccache->name = io_destination_ccache->name;
+ io_destination_ccache->name = temp_ccache.name;
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_source_ccache, io_cache_collection);
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_destination_ccache, io_cache_collection);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_release (ccs_ccache_t io_ccache)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_ccache) {
+ cci_identifier_release (io_ccache->identifier);
+ ccs_lock_state_release (io_ccache->lock_state);
+ free (io_ccache->name);
+ free (io_ccache->v4_principal);
+ free (io_ccache->v5_principal);
+ ccs_credentials_list_release (io_ccache->credentials);
+ ccs_callback_array_release (io_ccache->change_callbacks);
+ free (io_ccache);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_compare_identifier (ccs_ccache_t in_ccache,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier) { err = cci_check_error (ccErrBadParam); }
+ if (!out_equal ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_compare (in_ccache->identifier,
+ in_identifier,
+ out_equal);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_compare_name (ccs_ccache_t in_ccache,
+ const char *in_name,
+ cc_uint32 *out_equal)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_ccache) { err = cci_check_error (ccErrBadParam); }
+ if (!in_name ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_equal) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_equal = (strcmp (in_ccache->name, in_name) == 0);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_changed (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection)
+{
+ cc_int32 err = ccNoError;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_time_t now = time (NULL);
+
+ if (io_ccache->last_changed_time < now) {
+ io_ccache->last_changed_time = now;
+ } else {
+ io_ccache->last_changed_time++;
+ }
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_changed (io_cache_collection);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_new (&reply_data);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_time (reply_data, io_ccache->last_changed_time);
+ }
+
+ if (!err) {
+ /* Loop over callbacks sending messages to them */
+ cc_uint64 i;
+ cc_uint64 count = ccs_callback_array_count (io_ccache->change_callbacks);
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_callback_t callback = ccs_callback_array_object_at_index (io_ccache->change_callbacks, i);
+
+ err = ccs_callback_reply_to_client (callback, reply_data);
+
+ if (!err) {
+ cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
+ err = ccs_callback_array_remove (io_ccache->change_callbacks, i);
+ break;
+ }
+ }
+ }
+
+ if (!err) {
+ err = ccs_os_notify_ccache_changed (io_cache_collection,
+ io_ccache->name);
+ }
+
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_invalidate_change_callback (ccs_callback_owner_t io_ccache,
+ ccs_callback_t in_callback)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_callback) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ /* Remove callback */
+ ccs_ccache_t ccache = (ccs_ccache_t) io_ccache;
+ cc_uint64 i;
+ cc_uint64 count = ccs_callback_array_count (ccache->change_callbacks);
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_callback_t callback = ccs_callback_array_object_at_index (ccache->change_callbacks, i);
+
+ if (callback == in_callback) {
+ cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
+ err = ccs_callback_array_remove (ccache->change_callbacks, i);
+ break;
+ }
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_notify_default_state_changed (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ cc_uint32 in_new_default_state)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err && in_new_default_state) {
+ cc_time_t now = time (NULL);
+
+ if (io_ccache->last_default_time < now) {
+ io_ccache->last_default_time = now;
+ } else {
+ io_ccache->last_default_time++;
+ }
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_find_credentials_iterator (ccs_ccache_t in_ccache,
+ cci_identifier_t in_identifier,
+ ccs_credentials_iterator_t *out_credentials_iterator)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_credentials_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_credentials_list_find_iterator (in_ccache->credentials,
+ in_identifier,
+ out_credentials_iterator);
+ }
+
+ // Don't report ccErrInvalidCredentials to the log file. Non-fatal.
+ return (err == ccErrInvalidCredentials) ? err : cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_write (ccs_ccache_t in_ccache,
+ k5_ipc_stream io_stream)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_ccache) { err = cci_check_error (ccErrBadParam); }
+ if (!io_stream) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_write (in_ccache->identifier, io_stream);
+ }
+
+ return cci_check_error (err);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_write_name (ccs_ccache_t in_ccache,
+ k5_ipc_stream io_stream)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_ccache) { err = cci_check_error (ccErrBadParam); }
+ if (!io_stream) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_string (io_stream, in_ccache->name);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#pragma mark -- IPC Messages --
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_destroy (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_destroy_ccache (io_cache_collection,
+ io_ccache->identifier);
+ }
+
+ if (!err) {
+ /* ccache has been destroyed so just mark the cache collection */
+ err = ccs_cache_collection_changed (io_cache_collection);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_set_default (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_cache_collection_set_default_ccache (io_cache_collection,
+ io_ccache->identifier);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_get_credentials_version (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_uint32 (io_reply_data, io_ccache->creds_version);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_get_name (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_string (io_reply_data, io_ccache->name);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_get_principal (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 version = 0;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &version);
+ }
+
+ if (!err && version == cc_credentials_v4_v5) {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+
+ if (!err) {
+ if (version == cc_credentials_v4) {
+ err = krb5int_ipc_stream_write_string (io_reply_data, io_ccache->v4_principal);
+
+ } else if (version == cc_credentials_v5) {
+ err = krb5int_ipc_stream_write_string (io_reply_data, io_ccache->v5_principal);
+
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_set_principal (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 version = 0;
+ char *principal = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &version);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_string (in_request_data, &principal);
+ }
+
+ if (!err) {
+ /* reset KDC time offsets because they are per-KDC */
+ if (version == cc_credentials_v4) {
+ io_ccache->kdc_time_offset_v4 = 0;
+ io_ccache->kdc_time_offset_v4_valid = 0;
+
+ if (io_ccache->v4_principal) { free (io_ccache->v4_principal); }
+ io_ccache->v4_principal = principal;
+ principal = NULL; /* take ownership */
+
+
+ } else if (version == cc_credentials_v5) {
+ io_ccache->kdc_time_offset_v5 = 0;
+ io_ccache->kdc_time_offset_v5_valid = 0;
+
+ if (io_ccache->v5_principal) { free (io_ccache->v5_principal); }
+ io_ccache->v5_principal = principal;
+ principal = NULL; /* take ownership */
+
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ if (!err) {
+ io_ccache->creds_version |= version;
+
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ krb5int_ipc_stream_free_string (principal);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_store_credentials (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_credentials_t credentials = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_credentials_new (&credentials, in_request_data,
+ io_ccache->creds_version,
+ io_ccache->credentials);
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_remove_credentials (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cci_identifier_t credentials_identifier = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_read (&credentials_identifier, in_request_data);
+ }
+
+ if (!err) {
+ err = ccs_credentials_list_remove (io_ccache->credentials, credentials_identifier);
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ cci_identifier_release (credentials_identifier);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_new_credentials_iterator (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ ccs_pipe_t in_client_pipe,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_credentials_iterator_t credentials_iterator = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_credentials_list_new_iterator (io_ccache->credentials,
+ in_client_pipe,
+ &credentials_iterator);
+ }
+
+ if (!err) {
+ err = ccs_credentials_list_iterator_write (credentials_iterator, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_move (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cci_identifier_t source_identifier = NULL;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ /* Note: message is sent as the destination ccache to avoid */
+ /* extra work on the server when deleting it the source ccache. */
+ err = cci_identifier_read (&source_identifier, in_request_data);
+ }
+
+ if (!err) {
+ err = ccs_ccache_collection_move_ccache (io_cache_collection,
+ source_identifier,
+ io_ccache);
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ cci_identifier_release (source_identifier);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_lock (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 lock_type;
+ cc_uint32 block;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &lock_type);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &block);
+ }
+
+ if (!err) {
+ err = ccs_lock_state_add (io_ccache->lock_state,
+ in_client_pipe, in_reply_pipe,
+ lock_type, block, out_will_block);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_unlock (ccs_pipe_t in_client_pipe,
+ ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_lock_state_remove (io_ccache->lock_state, in_client_pipe);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_get_last_default_time (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err && io_ccache->last_default_time == 0) {
+ err = cci_check_error (ccErrNeverDefault);
+ }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_default_time);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_get_change_time (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_changed_time);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_wait_for_change (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data,
+ cc_uint32 *out_will_block)
+{
+ cc_int32 err = ccNoError;
+ cc_time_t last_wait_for_change_time = 0;
+ cc_uint32 will_block = 0;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe )) { err = cci_check_error (ccErrBadParam); }
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_time (in_request_data, &last_wait_for_change_time);
+ }
+
+ if (!err) {
+ if (last_wait_for_change_time < io_ccache->last_changed_time) {
+ cci_debug_printf ("%s returning immediately", __FUNCTION__);
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->last_changed_time);
+
+ } else {
+ ccs_callback_t callback = NULL;
+
+ err = ccs_callback_new (&callback,
+ ccErrInvalidCCache,
+ in_client_pipe,
+ in_reply_pipe,
+ (ccs_callback_owner_t) io_ccache,
+ ccs_ccache_invalidate_change_callback);
+
+ if (!err) {
+ err = ccs_callback_array_insert (io_ccache->change_callbacks, callback,
+ ccs_callback_array_count (io_ccache->change_callbacks));
+ if (!err) { callback = NULL; /* take ownership */ }
+
+ cci_debug_printf ("%s blocking", __FUNCTION__);
+ will_block = 1;
+ }
+
+ ccs_callback_release (callback);
+ }
+ }
+
+ if (!err) {
+ *out_will_block = will_block;
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_get_kdc_time_offset (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 cred_vers = 0;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
+ }
+
+ if (!err) {
+ if (cred_vers == cc_credentials_v4) {
+ if (io_ccache->kdc_time_offset_v4_valid) {
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->kdc_time_offset_v4);
+ } else {
+ err = cci_check_error (ccErrTimeOffsetNotSet);
+ }
+
+ } else if (cred_vers == cc_credentials_v5) {
+ if (io_ccache->kdc_time_offset_v5_valid) {
+ err = krb5int_ipc_stream_write_time (io_reply_data, io_ccache->kdc_time_offset_v5);
+ } else {
+ err = cci_check_error (ccErrTimeOffsetNotSet);
+ }
+
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_set_kdc_time_offset (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 cred_vers = 0;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
+ }
+
+ if (!err) {
+ if (cred_vers == cc_credentials_v4) {
+ err = krb5int_ipc_stream_read_time (in_request_data, &io_ccache->kdc_time_offset_v4);
+
+ if (!err) {
+ io_ccache->kdc_time_offset_v4_valid = 1;
+ }
+ } else if (cred_vers == cc_credentials_v5) {
+ err = krb5int_ipc_stream_read_time (in_request_data, &io_ccache->kdc_time_offset_v5);
+
+ if (!err) {
+ io_ccache->kdc_time_offset_v5_valid = 1;
+ }
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_clear_kdc_time_offset (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 cred_vers = 0;
+
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_read_uint32 (in_request_data, &cred_vers);
+ }
+
+ if (!err) {
+ if (cred_vers == cc_credentials_v4) {
+ io_ccache->kdc_time_offset_v4 = 0;
+ io_ccache->kdc_time_offset_v4_valid = 0;
+
+ } else if (cred_vers == cc_credentials_v5) {
+ io_ccache->kdc_time_offset_v5 = 0;
+ io_ccache->kdc_time_offset_v5_valid = 0;
+
+ } else {
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+ }
+
+ if (!err) {
+ err = ccs_ccache_changed (io_ccache, io_cache_collection);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_handle_message (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream *out_reply_data)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 will_block = 0;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_new (&reply_data);
+ }
+
+ if (!err) {
+ if (in_request_name == cci_ccache_destroy_msg_id) {
+ err = ccs_ccache_destroy (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_set_default_msg_id) {
+ err = ccs_ccache_set_default (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_get_credentials_version_msg_id) {
+ err = ccs_ccache_get_credentials_version (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_get_name_msg_id) {
+ err = ccs_ccache_get_name (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_get_principal_msg_id) {
+ err = ccs_ccache_get_principal (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_set_principal_msg_id) {
+ err = ccs_ccache_set_principal (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_store_credentials_msg_id) {
+ err = ccs_ccache_store_credentials (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_remove_credentials_msg_id) {
+ err = ccs_ccache_remove_credentials (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_new_credentials_iterator_msg_id) {
+ err = ccs_ccache_new_credentials_iterator (io_ccache,
+ io_cache_collection,
+ in_client_pipe,
+ in_request_data,
+ reply_data);
+
+ } else if (in_request_name == cci_ccache_move_msg_id) {
+ err = ccs_ccache_move (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_lock_msg_id) {
+ err = ccs_ccache_lock (in_client_pipe, in_reply_pipe,
+ io_ccache, io_cache_collection,
+ in_request_data,
+ &will_block, reply_data);
+
+ } else if (in_request_name == cci_ccache_unlock_msg_id) {
+ err = ccs_ccache_unlock (in_client_pipe,
+ io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_get_last_default_time_msg_id) {
+ err = ccs_ccache_get_last_default_time (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_get_change_time_msg_id) {
+ err = ccs_ccache_get_change_time (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_wait_for_change_msg_id) {
+ err = ccs_ccache_wait_for_change (in_client_pipe, in_reply_pipe,
+ io_ccache, io_cache_collection,
+ in_request_data, reply_data,
+ &will_block);
+
+ } else if (in_request_name == cci_ccache_get_kdc_time_offset_msg_id) {
+ err = ccs_ccache_get_kdc_time_offset (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_set_kdc_time_offset_msg_id) {
+ err = ccs_ccache_set_kdc_time_offset (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else if (in_request_name == cci_ccache_clear_kdc_time_offset_msg_id) {
+ err = ccs_ccache_clear_kdc_time_offset (io_ccache, io_cache_collection,
+ in_request_data, reply_data);
+
+ } else {
+ err = ccErrBadInternalMessage;
+ }
+ }
+
+ if (!err) {
+ *out_will_block = will_block;
+ if (!will_block) {
+ *out_reply_data = reply_data;
+ reply_data = NULL; /* take ownership */
+ } else {
+ *out_reply_data = NULL;
+ }
+ }
+
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_ccache.h b/src/ccapi/server/ccs_ccache.h
new file mode 100644
index 000000000000..8dab0651d6fb
--- /dev/null
+++ b/src/ccapi/server/ccs_ccache.h
@@ -0,0 +1,82 @@
+/* ccapi/server/ccs_ccache.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CCACHE_H
+#define CCS_CCACHE_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_ccache_new (ccs_ccache_t *out_ccache,
+ cc_uint32 in_cred_vers,
+ const char *in_name,
+ const char *in_principal,
+ ccs_ccache_list_t io_ccache_list);
+
+cc_int32 ccs_ccache_reset (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ cc_uint32 in_cred_vers,
+ const char *in_principal);
+
+cc_int32 ccs_ccache_swap_contents (ccs_ccache_t io_source_ccache,
+ ccs_ccache_t io_destination_ccache,
+ ccs_cache_collection_t io_cache_collection);
+
+cc_int32 ccs_ccache_release (ccs_ccache_t io_ccache);
+
+cc_int32 ccs_ccache_changed (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection);
+
+cc_int32 ccs_ccache_compare_identifier (ccs_ccache_t in_ccache,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal);
+
+cc_int32 ccs_ccache_compare_name (ccs_ccache_t in_ccache,
+ const char *in_name,
+ cc_uint32 *out_equal);
+
+cc_int32 ccs_ccache_notify_default_state_changed (ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ cc_uint32 in_new_default_state);
+
+cc_int32 ccs_ccache_find_credentials_iterator (ccs_ccache_t in_ccache,
+ cci_identifier_t in_identifier,
+ ccs_credentials_iterator_t *out_credentials_iterator);
+
+cc_int32 ccs_ccache_write (ccs_ccache_t in_ccache,
+ k5_ipc_stream io_stream);
+
+cc_int32 ccs_ccache_write_name (ccs_ccache_t in_ccache,
+ k5_ipc_stream io_stream);
+
+cc_int32 ccs_ccache_handle_message (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_ccache_t io_ccache,
+ ccs_cache_collection_t io_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream *out_reply_data);
+
+#endif /* CCS_CCACHE_H */
diff --git a/src/ccapi/server/ccs_ccache_iterator.c b/src/ccapi/server/ccs_ccache_iterator.c
new file mode 100644
index 000000000000..172e68a87e27
--- /dev/null
+++ b/src/ccapi/server/ccs_ccache_iterator.c
@@ -0,0 +1,156 @@
+/* ccapi/server/ccs_ccache_iterator.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_iterator_release (ccs_ccache_iterator_t io_ccache_iterator,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_ccache_iterator ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_iterator_release (io_ccache_iterator);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_iterator_next (ccs_ccache_iterator_t io_ccache_iterator,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_t ccache = NULL;
+
+ if (!io_ccache_iterator ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_iterator_next (io_ccache_iterator, &ccache);
+ }
+
+ if (!err) {
+ err = ccs_ccache_write (ccache, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_iterator_clone (ccs_ccache_iterator_t io_ccache_iterator,
+ ccs_cache_collection_t io_cache_collection,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_ccache_iterator_t ccache_iterator = NULL;
+
+ if (!io_ccache_iterator ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_ccache_list_iterator_clone (io_ccache_iterator,
+ &ccache_iterator);
+ }
+
+ if (!err) {
+ err = ccs_ccache_list_iterator_write (ccache_iterator, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+ cc_int32 ccs_ccache_iterator_handle_message (ccs_ccache_iterator_t io_ccache_iterator,
+ ccs_cache_collection_t io_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream *out_reply_data)
+{
+ cc_int32 err = ccNoError;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!in_request_data) { err = cci_check_error (ccErrBadParam); }
+ if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_new (&reply_data);
+ }
+
+ if (!err) {
+ if (in_request_name == cci_ccache_iterator_release_msg_id) {
+ err = ccs_ccache_iterator_release (io_ccache_iterator,
+ io_cache_collection,
+ in_request_data,
+ reply_data);
+
+ } else if (in_request_name == cci_ccache_iterator_next_msg_id) {
+ err = ccs_ccache_iterator_next (io_ccache_iterator,
+ io_cache_collection,
+ in_request_data,
+ reply_data);
+
+ } else if (in_request_name == cci_ccache_iterator_clone_msg_id) {
+ err = ccs_ccache_iterator_clone (io_ccache_iterator,
+ io_cache_collection,
+ in_request_data,
+ reply_data);
+
+ } else {
+ err = ccErrBadInternalMessage;
+ }
+ }
+
+ if (!err) {
+ *out_reply_data = reply_data;
+ reply_data = NULL; /* take ownership */
+ }
+
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_ccache_iterator.h b/src/ccapi/server/ccs_ccache_iterator.h
new file mode 100644
index 000000000000..96bf929db8cd
--- /dev/null
+++ b/src/ccapi/server/ccs_ccache_iterator.h
@@ -0,0 +1,37 @@
+/* ccapi/server/ccs_ccache_iterator.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CCACHE_ITERATOR_H
+#define CCS_CCACHE_ITERATOR_H
+
+#include "ccs_types.h"
+
+ cc_int32 ccs_ccache_iterator_handle_message (ccs_ccache_iterator_t io_ccache_iterator,
+ ccs_cache_collection_t io_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream *out_reply_data);
+
+#endif /* CCS_CCACHE_ITERATOR_H */
diff --git a/src/ccapi/server/ccs_client.c b/src/ccapi/server/ccs_client.c
new file mode 100644
index 000000000000..a7b0ad0bd438
--- /dev/null
+++ b/src/ccapi/server/ccs_client.c
@@ -0,0 +1,236 @@
+/* ccapi/server/ccs_client.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+
+struct ccs_client_d {
+ ccs_pipe_t client_pipe;
+
+ /* The following arrays do not own their contents */
+ ccs_callbackref_array_t callbacks;
+ ccs_iteratorref_array_t iterators;
+};
+
+struct ccs_client_d ccs_client_initializer = { CCS_PIPE_NULL, NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_new (ccs_client_t *out_client,
+ ccs_pipe_t in_client_pipe)
+{
+ cc_int32 err = ccNoError;
+ ccs_client_t client = NULL;
+
+ if (!out_client ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ client = malloc (sizeof (*client));
+ if (client) {
+ *client = ccs_client_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = ccs_callbackref_array_new (&client->callbacks);
+ }
+
+ if (!err) {
+ err = ccs_iteratorref_array_new (&client->iterators);
+ }
+
+ if (!err) {
+ err = ccs_pipe_copy (&client->client_pipe, in_client_pipe);
+ }
+
+ if (!err) {
+ *out_client = client;
+ client = NULL;
+ }
+
+ ccs_client_release (client);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_release (ccs_client_t io_client)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_client) {
+ cc_uint64 i;
+ cc_uint64 callback_count = ccs_callbackref_array_count (io_client->callbacks);
+ cc_uint64 iterator_count = ccs_iteratorref_array_count (io_client->iterators);
+
+ for (i = 0; !err && i < callback_count; i++) {
+ ccs_callback_t callback = ccs_callbackref_array_object_at_index (io_client->callbacks, i);
+
+ cci_debug_printf ("%s: Invalidating callback reference %p.",
+ __FUNCTION__, callback);
+ ccs_callback_invalidate (callback);
+ }
+
+ for (i = 0; !err && i < iterator_count; i++) {
+ ccs_generic_list_iterator_t iterator = ccs_iteratorref_array_object_at_index (io_client->iterators, i);
+
+ cci_debug_printf ("%s: Invalidating iterator reference %p.",
+ __FUNCTION__, iterator);
+ ccs_generic_list_iterator_invalidate (iterator);
+ }
+
+ ccs_callbackref_array_release (io_client->callbacks);
+ ccs_iteratorref_array_release (io_client->iterators);
+ ccs_pipe_release (io_client->client_pipe);
+ free (io_client);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_add_callback (ccs_client_t io_client,
+ ccs_callback_t in_callback)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_client ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_callback) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_callbackref_array_insert (io_client->callbacks, in_callback,
+ ccs_callbackref_array_count (io_client->callbacks));
+ }
+
+ return cci_check_error (err);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_remove_callback (ccs_client_t io_client,
+ ccs_callback_t in_callback)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 found_callback = 0;
+
+ if (!io_client) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_uint64 i;
+ cc_uint64 lock_count = ccs_callbackref_array_count (io_client->callbacks);
+
+ for (i = 0; !err && i < lock_count; i++) {
+ ccs_callback_t callback = ccs_callbackref_array_object_at_index (io_client->callbacks, i);
+
+ if (callback == in_callback) {
+ cci_debug_printf ("%s: Removing callback reference %p.", __FUNCTION__, callback);
+ found_callback = 1;
+ err = ccs_callbackref_array_remove (io_client->callbacks, i);
+ break;
+ }
+ }
+ }
+
+ if (!err && !found_callback) {
+ cci_debug_printf ("%s: WARNING! callback not found.", __FUNCTION__);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_add_iterator (ccs_client_t io_client,
+ ccs_generic_list_iterator_t in_iterator)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_client ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_iteratorref_array_insert (io_client->iterators, in_iterator,
+ ccs_iteratorref_array_count (io_client->iterators));
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_remove_iterator (ccs_client_t io_client,
+ ccs_generic_list_iterator_t in_iterator)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 found_iterator = 0;
+
+ if (!io_client) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_uint64 i;
+ cc_uint64 lock_count = ccs_iteratorref_array_count (io_client->iterators);
+
+ for (i = 0; !err && i < lock_count; i++) {
+ ccs_generic_list_iterator_t iterator = ccs_iteratorref_array_object_at_index (io_client->iterators, i);
+
+ if (iterator == in_iterator) {
+ cci_debug_printf ("%s: Removing iterator reference %p.", __FUNCTION__, iterator);
+ found_iterator = 1;
+ err = ccs_iteratorref_array_remove (io_client->iterators, i);
+ break;
+ }
+ }
+ }
+
+ if (!err && !found_iterator) {
+ cci_debug_printf ("%s: WARNING! iterator not found.", __FUNCTION__);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_client_uses_pipe (ccs_client_t in_client,
+ ccs_pipe_t in_pipe,
+ cc_uint32 *out_uses_pipe)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_client ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_pipe ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_uses_pipe) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_pipe_compare (in_client->client_pipe, in_pipe, out_uses_pipe);
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_client.h b/src/ccapi/server/ccs_client.h
new file mode 100644
index 000000000000..b6070daadf06
--- /dev/null
+++ b/src/ccapi/server/ccs_client.h
@@ -0,0 +1,52 @@
+/* ccapi/server/ccs_client.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CLIENT_H
+#define CCS_CLIENT_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_client_new (ccs_client_t *out_client,
+ ccs_pipe_t in_client_pipe);
+
+cc_int32 ccs_client_release (ccs_client_t io_client);
+
+cc_int32 ccs_client_add_callback (ccs_client_t io_client,
+ ccs_callback_t in_lock);
+
+cc_int32 ccs_client_remove_callback (ccs_client_t io_client,
+ ccs_callback_t in_lock);
+
+cc_int32 ccs_client_add_iterator (ccs_client_t io_client,
+ ccs_generic_list_iterator_t in_iterator);
+
+cc_int32 ccs_client_remove_iterator (ccs_client_t io_client,
+ ccs_generic_list_iterator_t in_iterator);
+
+cc_int32 ccs_client_uses_pipe (ccs_client_t in_client,
+ ccs_pipe_t in_pipe,
+ cc_uint32 *out_uses_pipe);
+
+#endif /* CCS_CLIENT_H */
diff --git a/src/ccapi/server/ccs_common.h b/src/ccapi/server/ccs_common.h
new file mode 100644
index 000000000000..eafecd8373ba
--- /dev/null
+++ b/src/ccapi/server/ccs_common.h
@@ -0,0 +1,47 @@
+/* ccapi/server/ccs_common.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_COMMON_H
+#define CCS_COMMON_H
+
+#include "cci_common.h"
+
+#include <time.h>
+
+#include "ccs_array.h"
+#include "ccs_list.h"
+#include "ccs_cache_collection.h"
+#include "ccs_ccache_iterator.h"
+#include "ccs_ccache.h"
+#include "ccs_credentials_iterator.h"
+#include "ccs_credentials.h"
+#include "ccs_lock.h"
+#include "ccs_lock_state.h"
+#include "ccs_pipe.h"
+#include "ccs_client.h"
+#include "ccs_callback.h"
+#include "ccs_server.h"
+
+#endif /* CCS_COMMON_H */
diff --git a/src/ccapi/server/ccs_credentials.c b/src/ccapi/server/ccs_credentials.c
new file mode 100644
index 000000000000..2c68e0f9b7c5
--- /dev/null
+++ b/src/ccapi/server/ccs_credentials.c
@@ -0,0 +1,139 @@
+/* ccapi/server/ccs_credentials.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+
+struct ccs_credentials_d {
+ cc_credentials_union *cred_union;
+ cci_identifier_t identifier;
+};
+
+struct ccs_credentials_d ccs_credentials_initializer = { NULL, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_new (ccs_credentials_t *out_credentials,
+ k5_ipc_stream in_stream,
+ cc_uint32 in_ccache_version,
+ ccs_credentials_list_t io_credentials_list)
+{
+ cc_int32 err = ccNoError;
+ ccs_credentials_t credentials = NULL;
+
+ if (!out_credentials) { err = cci_check_error (ccErrBadParam); }
+ if (!in_stream ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ credentials = malloc (sizeof (*credentials));
+ if (credentials) {
+ *credentials = ccs_credentials_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = cci_credentials_union_read (&credentials->cred_union, in_stream);
+ }
+
+ if (!err && !(credentials->cred_union->version & in_ccache_version)) {
+ /* ccache does not have a principal set for this credentials version */
+ err = cci_check_error (ccErrBadCredentialsVersion);
+ }
+
+ if (!err) {
+ err = ccs_server_new_identifier (&credentials->identifier);
+ }
+
+ if (!err) {
+ err = ccs_credentials_list_add (io_credentials_list, credentials);
+ }
+
+ if (!err) {
+ *out_credentials = credentials;
+ credentials = NULL;
+ }
+
+ ccs_credentials_release (credentials);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_release (ccs_credentials_t io_credentials)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_credentials) {
+ cci_credentials_union_release (io_credentials->cred_union);
+ cci_identifier_release (io_credentials->identifier);
+ free (io_credentials);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_write (ccs_credentials_t in_credentials,
+ k5_ipc_stream io_stream)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_credentials) { err = cci_check_error (ccErrBadParam); }
+ if (!io_stream ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_write (in_credentials->identifier, io_stream);
+ }
+
+ if (!err) {
+ err = cci_credentials_union_write (in_credentials->cred_union, io_stream);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_compare_identifier (ccs_credentials_t in_credentials,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_credentials) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_equal ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_compare (in_credentials->identifier,
+ in_identifier,
+ out_equal);
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_credentials.h b/src/ccapi/server/ccs_credentials.h
new file mode 100644
index 000000000000..5f096b860fb8
--- /dev/null
+++ b/src/ccapi/server/ccs_credentials.h
@@ -0,0 +1,46 @@
+/* ccapi/server/ccs_credentials.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CREDENTIALS_H
+#define CCS_CREDENTIALS_H
+
+#include "ccs_types.h"
+
+
+cc_int32 ccs_credentials_new (ccs_credentials_t *out_credentials,
+ k5_ipc_stream in_stream,
+ cc_uint32 in_ccache_version,
+ ccs_credentials_list_t io_credentials_list);
+
+cc_int32 ccs_credentials_release (ccs_credentials_t io_credentials);
+
+cc_int32 ccs_credentials_write (ccs_credentials_t in_credentials,
+ k5_ipc_stream io_stream);
+
+cc_int32 ccs_credentials_compare_identifier (ccs_credentials_t in_credentials,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal);
+
+#endif /* CCS_CREDENTIALS_H */
diff --git a/src/ccapi/server/ccs_credentials_iterator.c b/src/ccapi/server/ccs_credentials_iterator.c
new file mode 100644
index 000000000000..df18041cd73b
--- /dev/null
+++ b/src/ccapi/server/ccs_credentials_iterator.c
@@ -0,0 +1,158 @@
+/* ccapi/server/ccs_credentials_iterator.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_credentials_iterator_release (ccs_credentials_iterator_t io_credentials_iterator,
+ ccs_ccache_t io_ccache,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_credentials_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_credentials_list_iterator_release (io_credentials_iterator);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_credentials_iterator_next (ccs_credentials_iterator_t io_credentials_iterator,
+ ccs_ccache_t io_ccache,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_credentials_t credentials = NULL;
+
+ if (!io_credentials_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_credentials_list_iterator_next (io_credentials_iterator,
+ &credentials);
+ }
+
+ if (!err) {
+ err = ccs_credentials_write (credentials, io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_credentials_iterator_clone (ccs_credentials_iterator_t io_credentials_iterator,
+ ccs_ccache_t io_ccache,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream io_reply_data)
+{
+ cc_int32 err = ccNoError;
+ ccs_credentials_iterator_t credentials_iterator = NULL;
+
+ if (!io_credentials_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!io_ccache ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!io_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_credentials_list_iterator_clone (io_credentials_iterator,
+ &credentials_iterator);
+ }
+
+ if (!err) {
+ err = ccs_credentials_list_iterator_write (credentials_iterator,
+ io_reply_data);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+ cc_int32 ccs_credentials_iterator_handle_message (ccs_credentials_iterator_t io_credentials_iterator,
+ ccs_ccache_t io_ccache,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream *out_reply_data)
+{
+ cc_int32 err = ccNoError;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!in_request_data) { err = cci_check_error (ccErrBadParam); }
+ if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = krb5int_ipc_stream_new (&reply_data);
+ }
+
+ if (!err) {
+ if (in_request_name == cci_credentials_iterator_release_msg_id) {
+ err = ccs_credentials_iterator_release (io_credentials_iterator,
+ io_ccache,
+ in_request_data,
+ reply_data);
+
+ } else if (in_request_name == cci_credentials_iterator_next_msg_id) {
+ err = ccs_credentials_iterator_next (io_credentials_iterator,
+ io_ccache,
+ in_request_data,
+ reply_data);
+
+ } else if (in_request_name == cci_credentials_iterator_clone_msg_id) {
+ err = ccs_credentials_iterator_clone (io_credentials_iterator,
+ io_ccache,
+ in_request_data,
+ reply_data);
+
+ } else {
+ err = ccErrBadInternalMessage;
+ }
+ }
+
+ if (!err) {
+ *out_reply_data = reply_data;
+ reply_data = NULL; /* take ownership */
+ }
+
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_credentials_iterator.h b/src/ccapi/server/ccs_credentials_iterator.h
new file mode 100644
index 000000000000..fc81a82b7180
--- /dev/null
+++ b/src/ccapi/server/ccs_credentials_iterator.h
@@ -0,0 +1,37 @@
+/* ccapi/server/ccs_credentials_iterator.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_CREDENTIALS_ITERATOR_H
+#define CCS_CREDENTIALS_ITERATOR_H
+
+#include "ccs_types.h"
+
+ cc_int32 ccs_credentials_iterator_handle_message (ccs_credentials_iterator_t io_credentials_iterator,
+ ccs_ccache_t io_ccache,
+ enum cci_msg_id_t in_request_name,
+ k5_ipc_stream in_request_data,
+ k5_ipc_stream *out_reply_data);
+
+#endif /* CCS_CREDENTIALS_ITERATOR_H */
diff --git a/src/ccapi/server/ccs_list.c b/src/ccapi/server/ccs_list.c
new file mode 100644
index 000000000000..ef9a1906f1d3
--- /dev/null
+++ b/src/ccapi/server/ccs_list.c
@@ -0,0 +1,361 @@
+/* ccapi/server/ccs_list.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+#include "ccs_list_internal.h"
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_list_object_release (ccs_list_object_t io_object)
+{
+ return cci_check_error (ccs_cache_collection_release ((ccs_cache_collection_t) io_object));
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_cache_collection_list_object_compare_identifier (ccs_list_object_t in_cache_collection,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal)
+{
+ return ccs_cache_collection_compare_identifier ((ccs_cache_collection_t) in_cache_collection,
+ in_identifier,
+ out_equal);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_list_new (ccs_cache_collection_list_t *out_list)
+{
+ return ccs_list_new (out_list,
+ ccErrInvalidContext,
+ ccErrInvalidContext,
+ ccs_cache_collection_list_object_compare_identifier,
+ ccs_cache_collection_list_object_release);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_list_count (ccs_cache_collection_list_t in_list,
+ cc_uint64 *out_count)
+{
+ return ccs_list_count (in_list, out_count);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_list_find (ccs_cache_collection_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_cache_collection_t *out_cache_collection)
+{
+ return ccs_list_find (in_list, in_identifier, (ccs_list_object_t *) out_cache_collection);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_list_add (ccs_cache_collection_list_t io_list,
+ ccs_cache_collection_t in_cache_collection)
+{
+ return ccs_list_add (io_list, (ccs_list_object_t) in_cache_collection);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_list_remove (ccs_cache_collection_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ return ccs_list_remove (io_list, in_identifier);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_cache_collection_list_release (ccs_cache_collection_list_t io_list)
+{
+ return ccs_list_release (io_list);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_list_object_release (ccs_list_object_t io_ccache)
+{
+ return cci_check_error (ccs_ccache_release ((ccs_ccache_t) io_ccache));
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_ccache_list_object_compare_identifier (ccs_list_object_t in_ccache,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal)
+{
+ return ccs_ccache_compare_identifier ((ccs_ccache_t) in_ccache,
+ in_identifier,
+ out_equal);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_new (ccs_ccache_list_t *out_list)
+{
+ return ccs_list_new (out_list,
+ ccErrInvalidCCache,
+ ccErrInvalidCCacheIterator,
+ ccs_ccache_list_object_compare_identifier,
+ ccs_ccache_list_object_release);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_new_iterator (ccs_ccache_list_t in_list,
+ ccs_pipe_t in_client_pipe,
+ ccs_ccache_list_iterator_t *out_list_iterator)
+{
+ return ccs_list_new_iterator (in_list, in_client_pipe, out_list_iterator);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_count (ccs_ccache_list_t in_list,
+ cc_uint64 *out_count)
+{
+ return ccs_list_count (in_list, out_count);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_find (ccs_ccache_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_ccache_t *out_ccache)
+{
+ return ccs_list_find (in_list, in_identifier, (ccs_list_object_t *) out_ccache);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_find_iterator (ccs_ccache_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_ccache_list_iterator_t *out_list_iterator)
+{
+ return ccs_list_find_iterator (in_list, in_identifier,
+ (ccs_list_iterator_t *) out_list_iterator);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_add (ccs_ccache_list_t io_list,
+ ccs_ccache_t in_ccache)
+{
+ return ccs_list_add (io_list, (ccs_list_object_t) in_ccache);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_remove (ccs_ccache_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ return ccs_list_remove (io_list, in_identifier);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_push_front (ccs_ccache_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ return ccs_list_push_front (io_list, in_identifier);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_release (ccs_ccache_list_t io_list)
+{
+ return ccs_list_release (io_list);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_iterator_write (ccs_ccache_list_iterator_t in_list_iterator,
+ k5_ipc_stream in_stream)
+{
+ return ccs_list_iterator_write (in_list_iterator, in_stream);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_iterator_clone (ccs_ccache_list_iterator_t in_list_iterator,
+ ccs_ccache_list_iterator_t *out_list_iterator)
+{
+ return ccs_list_iterator_clone (in_list_iterator, out_list_iterator);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_iterator_next (ccs_ccache_list_iterator_t io_list_iterator,
+ ccs_ccache_t *out_ccache)
+{
+ return ccs_list_iterator_next (io_list_iterator, (ccs_list_object_t *) out_ccache);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_ccache_list_iterator_release (ccs_ccache_list_iterator_t io_list_iterator)
+{
+ return ccs_list_iterator_release (io_list_iterator);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark-
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_credentials_list_object_release (ccs_list_object_t io_object)
+{
+ return cci_check_error (ccs_credentials_release ((ccs_credentials_t) io_object));
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_credentials_list_object_compare_identifier (ccs_list_object_t in_credentials,
+ cci_identifier_t in_identifier,
+ cc_uint32 *out_equal)
+{
+ return ccs_credentials_compare_identifier ((ccs_credentials_t) in_credentials,
+ in_identifier,
+ out_equal);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_new (ccs_credentials_list_t *out_list)
+{
+ return ccs_list_new (out_list,
+ ccErrInvalidCredentials,
+ ccErrInvalidCredentialsIterator,
+ ccs_credentials_list_object_compare_identifier,
+ ccs_credentials_list_object_release);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_new_iterator (ccs_credentials_list_t in_list,
+ ccs_pipe_t in_client_pipe,
+ ccs_credentials_list_iterator_t *out_list_iterator)
+{
+ return ccs_list_new_iterator (in_list, in_client_pipe, out_list_iterator);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_count (ccs_credentials_list_t in_list,
+ cc_uint64 *out_count)
+{
+ return ccs_list_count (in_list, out_count);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_find (ccs_credentials_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_credentials_t *out_credentials)
+{
+ return ccs_list_find (in_list, in_identifier, (ccs_list_object_t *) out_credentials);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_find_iterator (ccs_credentials_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_credentials_list_iterator_t *out_list_iterator)
+{
+ return ccs_list_find_iterator (in_list, in_identifier,
+ (ccs_list_iterator_t *) out_list_iterator);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_add (ccs_credentials_list_t io_list,
+ ccs_credentials_t in_credential)
+{
+ return ccs_list_add (io_list, (ccs_list_object_t) in_credential);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_remove (ccs_credentials_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ return ccs_list_remove (io_list, in_identifier);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_release (ccs_credentials_list_t io_list)
+{
+ return ccs_list_release (io_list);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_iterator_write (ccs_credentials_list_iterator_t in_list_iterator,
+ k5_ipc_stream in_stream)
+{
+ return ccs_list_iterator_write (in_list_iterator, in_stream);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_iterator_clone (ccs_credentials_list_iterator_t in_list_iterator,
+ ccs_credentials_list_iterator_t *out_list_iterator)
+{
+ return ccs_list_iterator_clone (in_list_iterator, out_list_iterator);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_iterator_next (ccs_credentials_list_iterator_t io_list_iterator,
+ ccs_credentials_t *out_credential)
+{
+ return ccs_list_iterator_next (io_list_iterator, (ccs_list_object_t *) out_credential);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_credentials_list_iterator_release (ccs_credentials_list_iterator_t io_list_iterator)
+{
+ return ccs_list_iterator_release (io_list_iterator);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark-
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_generic_list_iterator_invalidate (ccs_generic_list_iterator_t io_list_iterator)
+{
+ return ccs_list_iterator_invalidate (io_list_iterator);
+}
diff --git a/src/ccapi/server/ccs_list.h b/src/ccapi/server/ccs_list.h
new file mode 100644
index 000000000000..7b818f92c9f9
--- /dev/null
+++ b/src/ccapi/server/ccs_list.h
@@ -0,0 +1,140 @@
+/* ccapi/server/ccs_list.h */
+/*
+ * Copyright 2006, 2007 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.
+ */
+
+#ifndef CCS_LIST_H
+#define CCS_LIST_H
+
+
+#include "ccs_types.h"
+
+cc_int32 ccs_cache_collection_list_new (ccs_cache_collection_list_t *out_list);
+
+cc_int32 ccs_cache_collection_list_count (ccs_cache_collection_list_t in_list,
+ cc_uint64 *out_count);
+
+cc_int32 ccs_cache_collection_list_find (ccs_cache_collection_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_cache_collection_t *out_cache_collection);
+
+cc_int32 ccs_cache_collection_list_add (ccs_cache_collection_list_t io_list,
+ ccs_cache_collection_t in_cache_collection);
+
+cc_int32 ccs_cache_collection_list_remove (ccs_cache_collection_list_t io_list,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_cache_collection_list_release (ccs_cache_collection_list_t io_list);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_ccache_list_new (ccs_ccache_list_t *out_list);
+
+cc_int32 ccs_ccache_list_new_iterator (ccs_ccache_list_t in_list,
+ ccs_pipe_t in_client_pipe,
+ ccs_ccache_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_ccache_list_count (ccs_ccache_list_t in_list,
+ cc_uint64 *out_count);
+
+cc_int32 ccs_ccache_list_find (ccs_ccache_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_ccache_t *out_ccache);
+
+cc_int32 ccs_ccache_list_find_iterator (ccs_ccache_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_ccache_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_ccache_list_add (ccs_ccache_list_t io_list,
+ ccs_ccache_t in_ccache);
+
+cc_int32 ccs_ccache_list_remove (ccs_ccache_list_t io_list,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_ccache_list_push_front (ccs_ccache_list_t io_list,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_ccache_list_release (ccs_ccache_list_t io_list);
+
+
+cc_int32 ccs_ccache_list_iterator_write (ccs_ccache_list_iterator_t in_list_iterator,
+ k5_ipc_stream in_stream);
+
+cc_int32 ccs_ccache_list_iterator_clone (ccs_ccache_list_iterator_t in_list_iterator,
+ ccs_ccache_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_ccache_list_iterator_next (ccs_ccache_list_iterator_t io_list_iterator,
+ ccs_ccache_t *out_ccache);
+
+cc_int32 ccs_ccache_list_iterator_release (ccs_ccache_list_iterator_t io_list_iterator);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_credentials_list_new (ccs_credentials_list_t *out_list);
+
+cc_int32 ccs_credentials_list_new_iterator (ccs_credentials_list_t in_list,
+ ccs_pipe_t in_client_pipe,
+ ccs_credentials_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_credentials_list_count (ccs_credentials_list_t in_list,
+ cc_uint64 *out_count);
+
+cc_int32 ccs_credentials_list_find (ccs_credentials_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_credentials_t *out_credentials);
+
+cc_int32 ccs_credentials_list_find_iterator (ccs_credentials_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_credentials_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_credentials_list_add (ccs_credentials_list_t io_list,
+ ccs_credentials_t in_credential);
+
+cc_int32 ccs_credentials_list_remove (ccs_credentials_list_t io_list,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_credentials_list_release (ccs_credentials_list_t io_list);
+
+
+cc_int32 ccs_credentials_list_iterator_write (ccs_credentials_list_iterator_t in_list_iterator,
+ k5_ipc_stream in_stream);
+
+cc_int32 ccs_credentials_list_iterator_clone (ccs_credentials_list_iterator_t in_list_iterator,
+ ccs_credentials_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_credentials_list_iterator_next (ccs_credentials_list_iterator_t io_list_iterator,
+ ccs_credentials_t *out_credential);
+
+cc_int32 ccs_credentials_list_iterator_release (ccs_credentials_list_iterator_t io_list_iterator);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+cc_int32 ccs_generic_list_iterator_invalidate (ccs_generic_list_iterator_t io_list_iterator);
+
+#endif /* CCS_LIST_H */
diff --git a/src/ccapi/server/ccs_list_internal.c b/src/ccapi/server/ccs_list_internal.c
new file mode 100644
index 000000000000..82d646522a9a
--- /dev/null
+++ b/src/ccapi/server/ccs_list_internal.c
@@ -0,0 +1,675 @@
+/* ccapi/server/ccs_list_internal.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_list_internal.h"
+#include "cci_array_internal.h"
+#include "cci_identifier.h"
+#include "ccs_server.h"
+
+typedef enum {
+ ccs_list_action_insert,
+ ccs_list_action_remove,
+ ccs_list_action_push_front
+} ccs_list_action_enum;
+
+/* ------------------------------------------------------------------------ */
+
+struct ccs_list_d {
+ cci_array_t objects;
+ cci_array_t iterators;
+
+ cc_int32 object_not_found_err;
+ cc_int32 iterator_not_found_err;
+
+ ccs_object_compare_identifier_t object_compare_identifier;
+};
+
+struct ccs_list_d ccs_list_initializer = { NULL, NULL, -1, -1, NULL };
+
+/* ------------------------------------------------------------------------ */
+
+struct ccs_list_iterator_d {
+ cci_identifier_t identifier;
+ ccs_pipe_t client_pipe;
+ ccs_list_t list;
+ cc_uint64 current;
+};
+
+struct ccs_list_iterator_d ccs_list_iterator_initializer = { NULL, CCS_PIPE_NULL, NULL, 0 };
+
+static cc_int32 ccs_list_iterator_new (ccs_list_iterator_t *out_list_iterator,
+ ccs_list_t in_list,
+ ccs_pipe_t in_client_pipe);
+
+static cc_int32 ccs_list_iterator_object_release (cci_array_object_t io_list_iterator);
+
+static cc_int32 ccs_list_iterator_update (ccs_list_iterator_t io_list_iterator,
+ ccs_list_action_enum in_action,
+ cc_uint64 in_object_index);
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_new (ccs_list_t *out_list,
+ cc_int32 in_object_not_found_err,
+ cc_int32 in_iterator_not_found_err,
+ ccs_object_compare_identifier_t in_object_compare_identifier,
+ ccs_object_release_t in_object_release)
+{
+ cc_int32 err = ccNoError;
+ ccs_list_t list = NULL;
+
+ if (!out_list) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ list = malloc (sizeof (*list));
+ if (list) {
+ *list = ccs_list_initializer;
+ list->object_not_found_err = in_object_not_found_err;
+ list->iterator_not_found_err = in_iterator_not_found_err;
+ list->object_compare_identifier = in_object_compare_identifier;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = cci_array_new (&list->objects, in_object_release);
+ }
+
+ if (!err) {
+ err = cci_array_new (&list->iterators, ccs_list_iterator_object_release);
+ }
+
+ if (!err) {
+ *out_list = list;
+ list = NULL;
+ }
+
+ ccs_list_release (list);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_release (ccs_list_t io_list)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_list) {
+ cci_array_release (io_list->iterators);
+ cci_array_release (io_list->objects);
+ free (io_list);
+ }
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_new_iterator (ccs_list_t io_list,
+ ccs_pipe_t in_client_pipe,
+ ccs_list_iterator_t *out_list_iterator)
+{
+ return cci_check_error (ccs_list_iterator_new (out_list_iterator,
+ io_list,
+ in_client_pipe));
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_release_iterator (ccs_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ cc_int32 err = ccNoError;
+ ccs_list_iterator_t iterator = NULL;
+
+ if (!io_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_list_find_iterator (io_list, in_identifier, &iterator);
+ }
+
+ if (!err) {
+ err = ccs_list_iterator_release (iterator);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_count (ccs_list_t in_list,
+ cc_uint64 *out_count)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_count) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_count = cci_array_count (in_list->objects);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static ccs_list_iterator_t ccs_list_iterator_at_index (ccs_list_t in_list,
+ cc_uint64 in_index)
+{
+ return (ccs_list_iterator_t) cci_array_object_at_index (in_list->iterators, in_index);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_list_find_index (ccs_list_t in_list,
+ cci_identifier_t in_identifier,
+ cc_uint64 *out_object_index)
+{
+ cc_int32 err = ccNoError;
+ cc_int32 found = 0;
+
+ if (!in_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_object_index) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err && !found) {
+ cc_uint64 i;
+
+ for (i = 0; !err && i < cci_array_count (in_list->objects); i++) {
+ cc_uint32 equal = 0;
+ cci_array_object_t object = cci_array_object_at_index (in_list->objects, i);
+
+ err = in_list->object_compare_identifier (object, in_identifier, &equal);
+
+ if (!err && equal) {
+ found = 1;
+ *out_object_index = i;
+ break;
+ }
+ }
+ }
+
+ if (!err && !found) {
+ err = cci_check_error (in_list->object_not_found_err);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+cc_int32 ccs_list_find (ccs_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_list_object_t *out_object)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 i;
+
+ if (!in_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier) { err = cci_check_error (ccErrBadParam); }
+ if (!out_object ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_list_find_index (in_list, in_identifier, &i);
+ }
+
+ if (!err) {
+ *out_object = cci_array_object_at_index (in_list->objects, i);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_list_find_iterator_index (ccs_list_t in_list,
+ cci_identifier_t in_identifier,
+ cc_uint64 *out_object_index)
+{
+ cc_int32 err = ccNoError;
+ cc_int32 found = 0;
+
+ if (!in_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_object_index) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err && !found) {
+ cc_uint64 i;
+
+ for (i = 0; !err && i < cci_array_count (in_list->iterators); i++) {
+ cc_uint32 equal = 0;
+ ccs_list_iterator_t iterator = ccs_list_iterator_at_index (in_list, i);
+
+ err = cci_identifier_compare (iterator->identifier, in_identifier, &equal);
+
+ if (!err && equal) {
+ found = 1;
+ *out_object_index = i;
+ break;
+ }
+ }
+ }
+
+ if (!err && !found) {
+ // Don't report this error to the log file. Non-fatal.
+ return in_list->object_not_found_err;
+ } else {
+ return cci_check_error (err);
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_find_iterator (ccs_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_list_iterator_t *out_list_iterator)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 i;
+
+ if (!in_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_list_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_list_find_iterator_index (in_list, in_identifier, &i);
+ }
+
+ if (!err) {
+ *out_list_iterator = ccs_list_iterator_at_index (in_list, i);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_add (ccs_list_t io_list,
+ ccs_list_object_t in_object)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 add_index;
+
+ if (!io_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_object) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ add_index = cci_array_count (io_list->objects);
+
+ err = cci_array_insert (io_list->objects, in_object, add_index);
+ }
+
+ if (!err) {
+ /* Fixup iterator indexes */
+ cc_uint64 i;
+
+ for (i = 0; !err && i < cci_array_count (io_list->iterators); i++) {
+ ccs_list_iterator_t iterator = ccs_list_iterator_at_index (io_list, i);
+
+ err = ccs_list_iterator_update (iterator, ccs_list_action_insert, add_index);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_remove (ccs_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 remove_index;
+
+ if (!io_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_list_find_index (io_list, in_identifier, &remove_index);
+ }
+
+ if (!err) {
+ err = cci_array_remove (io_list->objects, remove_index);
+ }
+
+ if (!err) {
+ /* Fixup iterator indexes */
+ cc_uint64 i;
+
+ for (i = 0; !err && i < cci_array_count (io_list->iterators); i++) {
+ ccs_list_iterator_t iterator = ccs_list_iterator_at_index (io_list, i);
+
+ err = ccs_list_iterator_update (iterator, ccs_list_action_remove, remove_index);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_push_front (ccs_list_t io_list,
+ cci_identifier_t in_identifier)
+{
+ cc_int32 err = ccNoError;
+ cc_uint64 push_front_index;
+
+ if (!io_list ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_identifier) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_list_find_index (io_list, in_identifier, &push_front_index);
+ }
+
+ if (!err) {
+ err = cci_array_push_front (io_list->objects, push_front_index);
+ }
+
+ if (!err) {
+ /* Fixup iterator indexes */
+ cc_uint64 i;
+
+ for (i = 0; !err && i < cci_array_count (io_list->iterators); i++) {
+ ccs_list_iterator_t iterator = ccs_list_iterator_at_index (io_list, i);
+
+ err = ccs_list_iterator_update (iterator,
+ ccs_list_action_push_front,
+ push_front_index);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_list_iterator_new (ccs_list_iterator_t *out_list_iterator,
+ ccs_list_t io_list,
+ ccs_pipe_t in_client_pipe)
+{
+ cc_int32 err = ccNoError;
+ ccs_list_iterator_t list_iterator = NULL;
+
+ if (!out_list_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!io_list ) { err = cci_check_error (ccErrBadParam); }
+ /* client_pipe may be NULL if the iterator exists for internal server use */
+
+ if (!err) {
+ list_iterator = malloc (sizeof (*list_iterator));
+ if (list_iterator) {
+ *list_iterator = ccs_list_iterator_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = ccs_server_new_identifier (&list_iterator->identifier);
+ }
+
+ if (!err) {
+ list_iterator->list = io_list;
+ list_iterator->current = 0;
+
+ err = cci_array_insert (io_list->iterators,
+ (cci_array_object_t) list_iterator,
+ cci_array_count (io_list->iterators));
+ }
+
+ if (!err && ccs_pipe_valid (in_client_pipe)) {
+ ccs_client_t client = NULL;
+
+ err = ccs_pipe_copy (&list_iterator->client_pipe, in_client_pipe);
+
+ if (!err) {
+ err = ccs_server_client_for_pipe (in_client_pipe, &client);
+ }
+
+ if (!err) {
+ err = ccs_client_add_iterator (client, list_iterator);
+ }
+ }
+
+ if (!err) {
+ *out_list_iterator = list_iterator;
+ list_iterator = NULL;
+ }
+
+ ccs_list_iterator_release (list_iterator);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_iterator_write (ccs_list_iterator_t in_list_iterator,
+ k5_ipc_stream in_stream)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_list_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!in_stream ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_identifier_write (in_list_iterator->identifier,
+ in_stream);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_iterator_clone (ccs_list_iterator_t in_list_iterator,
+ ccs_list_iterator_t *out_list_iterator)
+{
+ cc_int32 err = ccNoError;
+ ccs_list_iterator_t list_iterator = NULL;
+
+ if (!in_list_iterator ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_list_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_list_iterator_new (&list_iterator,
+ in_list_iterator->list,
+ in_list_iterator->client_pipe);
+ }
+
+ if (!err) {
+ list_iterator->current = in_list_iterator->current;
+
+ *out_list_iterator = list_iterator;
+ list_iterator = NULL;
+ }
+
+ ccs_list_iterator_release (list_iterator);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_list_iterator_object_release (cci_array_object_t io_list_iterator)
+{
+ cc_int32 err = ccNoError;
+ ccs_list_iterator_t list_iterator = (ccs_list_iterator_t) io_list_iterator;
+
+ if (!io_list_iterator) { err = ccErrBadParam; }
+
+ if (!err && ccs_pipe_valid (list_iterator->client_pipe)) {
+ ccs_client_t client = NULL;
+
+ err = ccs_server_client_for_pipe (list_iterator->client_pipe, &client);
+
+ if (!err && client) {
+ /* if client object still has a reference to us, remove it */
+ err = ccs_client_remove_iterator (client, list_iterator);
+ }
+ }
+
+ if (!err) {
+ ccs_pipe_release (list_iterator->client_pipe);
+ cci_identifier_release (list_iterator->identifier);
+ free (io_list_iterator);
+ }
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_iterator_release (ccs_list_iterator_t io_list_iterator)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_list_iterator) {
+ cc_uint64 i = 0;
+
+ if (ccs_list_find_iterator_index (io_list_iterator->list,
+ io_list_iterator->identifier,
+ &i) == ccNoError) {
+ /* cci_array_remove will call ccs_list_iterator_object_release */
+ err = cci_array_remove (io_list_iterator->list->iterators, i);
+ } else {
+ cci_debug_printf ("Warning: iterator not in iterator list!");
+ }
+ }
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_iterator_invalidate (ccs_list_iterator_t io_list_iterator)
+{
+ cc_int32 err = ccNoError;
+ ccs_list_iterator_t list_iterator = (ccs_list_iterator_t) io_list_iterator;
+
+ if (!io_list_iterator) { err = ccErrBadParam; }
+
+ if (!err) {
+ /* Client owner died. Remove client reference and then the iterator. */
+ if (ccs_pipe_valid (list_iterator->client_pipe)) {
+ ccs_pipe_release (list_iterator->client_pipe);
+ list_iterator->client_pipe = CCS_PIPE_NULL;
+ }
+
+ err = ccs_list_iterator_release (io_list_iterator);
+ }
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_iterator_current (ccs_list_iterator_t io_list_iterator,
+ ccs_list_object_t *out_object)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_list_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!out_object ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ if (io_list_iterator->current < cci_array_count (io_list_iterator->list->objects)) {
+ *out_object = cci_array_object_at_index (io_list_iterator->list->objects,
+ io_list_iterator->current);
+ } else {
+ err = ccIteratorEnd;
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_list_iterator_next (ccs_list_iterator_t io_list_iterator,
+ ccs_list_object_t *out_object)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_list_iterator) { err = cci_check_error (ccErrBadParam); }
+ if (!out_object ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ if (io_list_iterator->current < cci_array_count (io_list_iterator->list->objects)) {
+ *out_object = cci_array_object_at_index (io_list_iterator->list->objects,
+ io_list_iterator->current);
+ io_list_iterator->current++;
+ } else {
+ err = ccIteratorEnd;
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_list_iterator_update (ccs_list_iterator_t io_list_iterator,
+ ccs_list_action_enum in_action,
+ cc_uint64 in_object_index)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_list_iterator) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ /* When the list changes adjust the current index so that */
+ /* we don't unnecessarily skip or double count items */
+ if (in_action == ccs_list_action_insert) {
+ if (io_list_iterator->current > in_object_index) {
+ io_list_iterator->current++;
+ }
+
+ } else if (in_action == ccs_list_action_remove) {
+ if (io_list_iterator->current >= in_object_index) {
+ io_list_iterator->current--;
+ }
+
+ } else if (in_action == ccs_list_action_push_front) {
+ if (io_list_iterator->current < in_object_index) {
+ io_list_iterator->current++;
+ }
+
+ } else {
+ err = cci_check_error (ccErrBadParam);
+ }
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_list_internal.h b/src/ccapi/server/ccs_list_internal.h
new file mode 100644
index 000000000000..08cfa201c1e5
--- /dev/null
+++ b/src/ccapi/server/ccs_list_internal.h
@@ -0,0 +1,94 @@
+/* ccapi/server/ccs_list_internal.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_LIST_INTERNAL_H
+#define CCS_LIST_INTERNAL_H
+
+#include "ccs_common.h"
+#include "cci_array_internal.h"
+
+struct ccs_list_d;
+typedef struct ccs_list_d *ccs_list_t;
+
+struct ccs_list_iterator_d;
+typedef struct ccs_list_iterator_d *ccs_list_iterator_t;
+
+typedef cci_array_object_t ccs_list_object_t;
+typedef cc_int32 (*ccs_object_release_t) (ccs_list_object_t);
+typedef cc_int32 (*ccs_object_compare_identifier_t) (ccs_list_object_t, cci_identifier_t, cc_uint32 *);
+
+cc_int32 ccs_list_new (ccs_list_t *out_list,
+ cc_int32 in_object_not_found_err,
+ cc_int32 in_iterator_not_found_err,
+ ccs_object_compare_identifier_t in_object_compare_identifier,
+ ccs_object_release_t in_object_release);
+
+cc_int32 ccs_list_release (ccs_list_t io_list);
+
+cc_int32 ccs_list_new_iterator (ccs_list_t io_list,
+ ccs_pipe_t in_client_pipe,
+ ccs_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_list_release_iterator (ccs_list_t io_list,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_list_count (ccs_list_t in_list,
+ cc_uint64 *out_count);
+
+cc_int32 ccs_list_find (ccs_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_list_object_t *out_object);
+
+cc_int32 ccs_list_find_iterator (ccs_list_t in_list,
+ cci_identifier_t in_identifier,
+ ccs_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_list_add (ccs_list_t io_list,
+ ccs_list_object_t in_object);
+
+cc_int32 ccs_list_remove (ccs_list_t io_list,
+ cci_identifier_t in_identifier);
+
+cc_int32 ccs_list_push_front (ccs_list_t io_list,
+ cci_identifier_t in_identifier);
+
+
+cc_int32 ccs_list_iterator_write (ccs_list_iterator_t in_list_iterator,
+ k5_ipc_stream in_stream);
+
+cc_int32 ccs_list_iterator_clone (ccs_list_iterator_t in_list_iterator,
+ ccs_list_iterator_t *out_list_iterator);
+
+cc_int32 ccs_list_iterator_current (ccs_list_iterator_t io_list_iterator,
+ ccs_list_object_t *out_object);
+
+cc_int32 ccs_list_iterator_next (ccs_list_iterator_t io_list_iterator,
+ ccs_list_object_t *out_object);
+
+cc_int32 ccs_list_iterator_invalidate (ccs_list_iterator_t io_list_iterator);
+
+cc_int32 ccs_list_iterator_release (ccs_list_iterator_t io_list_iterator);
+
+#endif /* CCS_LIST_INTERNAL_H */
diff --git a/src/ccapi/server/ccs_lock.c b/src/ccapi/server/ccs_lock.c
new file mode 100644
index 000000000000..06886f8c7557
--- /dev/null
+++ b/src/ccapi/server/ccs_lock.c
@@ -0,0 +1,248 @@
+/* ccapi/server/ccs_lock.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+
+struct ccs_lock_d {
+ cc_uint32 type;
+ ccs_lock_state_t lock_state_owner;
+ ccs_callback_t callback;
+};
+
+struct ccs_lock_d ccs_lock_initializer = { 0, NULL, NULL };
+
+static cc_int32 ccs_lock_invalidate_callback (ccs_callback_owner_t io_lock,
+ ccs_callback_t in_callback);
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_new (ccs_lock_t *out_lock,
+ cc_uint32 in_type,
+ cc_int32 in_invalid_object_err,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_lock_state_t in_lock_state_owner)
+{
+ cc_int32 err = ccNoError;
+ ccs_lock_t lock = NULL;
+
+ if (!out_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_lock_state_owner ) { err = cci_check_error (ccErrBadParam); }
+
+ if (in_type != cc_lock_read &&
+ in_type != cc_lock_write &&
+ in_type != cc_lock_upgrade &&
+ in_type != cc_lock_downgrade) {
+ err = cci_check_error (ccErrBadLockType);
+ }
+
+ if (!err) {
+ lock = malloc (sizeof (*lock));
+ if (lock) {
+ *lock = ccs_lock_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ lock->type = in_type;
+ lock->lock_state_owner = in_lock_state_owner;
+
+ err = ccs_callback_new (&lock->callback,
+ in_invalid_object_err,
+ in_client_pipe,
+ in_reply_pipe,
+ (ccs_callback_owner_t) lock,
+ ccs_lock_invalidate_callback);
+ }
+
+ if (!err) {
+ *out_lock = lock;
+ lock = NULL;
+ }
+
+ ccs_lock_release (lock);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_release (ccs_lock_t io_lock)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_lock) {
+ ccs_callback_release (io_lock->callback);
+ free (io_lock);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_invalidate_callback (ccs_callback_owner_t io_lock,
+ ccs_callback_t in_callback)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_callback) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ ccs_lock_t lock = (ccs_lock_t) io_lock;
+
+ err = ccs_lock_state_invalidate_lock (lock->lock_state_owner, lock);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_grant_lock (ccs_lock_t io_lock)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_lock) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_callback_reply_to_client (io_lock->callback, NULL);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint32 ccs_lock_is_pending (ccs_lock_t in_lock,
+ cc_uint32 *out_pending)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_pending) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_callback_is_pending (in_lock->callback, out_pending);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_type (ccs_lock_t in_lock,
+ cc_uint32 *out_lock_type)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_lock_type) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_lock_type = in_lock->type;
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_is_read_lock (ccs_lock_t in_lock,
+ cc_uint32 *out_is_read_lock)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_is_read_lock) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_is_read_lock = (in_lock->type == cc_lock_read ||
+ in_lock->type == cc_lock_downgrade);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_is_write_lock (ccs_lock_t in_lock,
+ cc_uint32 *out_is_write_lock)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_is_write_lock) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_is_write_lock = (in_lock->type == cc_lock_write ||
+ in_lock->type == cc_lock_upgrade);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_is_for_client_pipe (ccs_lock_t in_lock,
+ ccs_pipe_t in_client_pipe,
+ cc_uint32 *out_is_for_client_pipe)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!out_is_for_client_pipe ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_callback_is_for_client_pipe (in_lock->callback, in_client_pipe,
+ out_is_for_client_pipe);
+ }
+
+ return cci_check_error (err);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_client_pipe (ccs_lock_t in_lock,
+ ccs_pipe_t *out_client_pipe)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_lock ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_client_pipe) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_callback_client_pipe (in_lock->callback, out_client_pipe);
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_lock.h b/src/ccapi/server/ccs_lock.h
new file mode 100644
index 000000000000..71863ab1bcf4
--- /dev/null
+++ b/src/ccapi/server/ccs_lock.h
@@ -0,0 +1,61 @@
+/* ccapi/server/ccs_lock.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_LOCK_H
+#define CCS_LOCK_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_lock_new (ccs_lock_t *out_lock,
+ cc_uint32 in_type,
+ cc_int32 in_invalid_object_err,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_lock_state_t in_lock_state_owner);
+
+cc_int32 ccs_lock_release (ccs_lock_t io_lock);
+
+cc_int32 ccs_lock_grant_lock (ccs_lock_t io_lock);
+
+cc_uint32 ccs_lock_is_pending (ccs_lock_t in_lock,
+ cc_uint32 *out_pending);
+
+cc_int32 ccs_lock_type (ccs_lock_t in_lock,
+ cc_uint32 *out_lock_type);
+
+cc_int32 ccs_lock_is_read_lock (ccs_lock_t in_lock,
+ cc_uint32 *out_is_read_lock);
+
+cc_int32 ccs_lock_is_write_lock (ccs_lock_t in_lock,
+ cc_uint32 *out_is_write_lock);
+
+cc_int32 ccs_lock_is_for_client_pipe (ccs_lock_t in_lock,
+ ccs_pipe_t in_client_pipe,
+ cc_uint32 *out_is_for_client_pipe);
+
+cc_int32 ccs_lock_client_pipe (ccs_lock_t in_lock,
+ ccs_pipe_t *out_client_pipe);
+
+#endif /* CCS_LOCK_H */
diff --git a/src/ccapi/server/ccs_lock_state.c b/src/ccapi/server/ccs_lock_state.c
new file mode 100644
index 000000000000..681661ea6b37
--- /dev/null
+++ b/src/ccapi/server/ccs_lock_state.c
@@ -0,0 +1,525 @@
+/* ccapi/server/ccs_lock_state.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+
+struct ccs_lock_state_d {
+ cc_int32 invalid_object_err;
+ cc_int32 pending_lock_err;
+ cc_int32 no_lock_err;
+ ccs_lock_array_t locks;
+ cc_uint64 first_pending_lock_index;
+};
+
+struct ccs_lock_state_d ccs_lock_state_initializer = { 1, 1, 1, NULL, 0 };
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_state_new (ccs_lock_state_t *out_lock_state,
+ cc_int32 in_invalid_object_err,
+ cc_int32 in_pending_lock_err,
+ cc_int32 in_no_lock_err)
+{
+ cc_int32 err = ccNoError;
+ ccs_lock_state_t lock_state = NULL;
+
+ if (!out_lock_state) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ lock_state = malloc (sizeof (*lock_state));
+ if (lock_state) {
+ *lock_state = ccs_lock_state_initializer;
+ } else {
+ err = cci_check_error (ccErrNoMem);
+ }
+ }
+
+ if (!err) {
+ err = ccs_lock_array_new (&lock_state->locks);
+ }
+
+ if (!err) {
+ lock_state->invalid_object_err = in_invalid_object_err;
+ lock_state->pending_lock_err = in_pending_lock_err;
+ lock_state->no_lock_err = in_no_lock_err;
+
+ *out_lock_state = lock_state;
+ lock_state = NULL;
+ }
+
+ ccs_lock_state_release (lock_state);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_state_release (ccs_lock_state_t io_lock_state)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err && io_lock_state) {
+ ccs_lock_array_release (io_lock_state->locks);
+ free (io_lock_state);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_status_add_pending_lock (ccs_lock_state_t io_lock_state,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ cc_uint32 in_lock_type,
+ cc_uint64 *out_lock_index)
+{
+ cc_int32 err = ccNoError;
+ ccs_lock_t lock = NULL;
+
+ if (!io_lock_state ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_lock_new (&lock, in_lock_type,
+ io_lock_state->invalid_object_err,
+ in_client_pipe, in_reply_pipe,
+ io_lock_state);
+ }
+
+ if (!err) {
+ err = ccs_lock_array_insert (io_lock_state->locks, lock,
+ ccs_lock_array_count (io_lock_state->locks));
+ if (!err) { lock = NULL; /* take ownership */ }
+ }
+
+ if (!err) {
+ *out_lock_index = ccs_lock_array_count (io_lock_state->locks) - 1;
+ }
+
+ ccs_lock_release (lock);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_status_remove_lock (ccs_lock_state_t io_lock_state,
+ cc_uint64 in_lock_index)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_lock_state) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_lock_array_remove (io_lock_state->locks, in_lock_index);
+
+ if (!err && in_lock_index < io_lock_state->first_pending_lock_index) {
+ io_lock_state->first_pending_lock_index--;
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_status_grant_lock (ccs_lock_state_t io_lock_state,
+ cc_uint64 in_pending_lock_index)
+{
+ cc_int32 err = ccNoError;
+ ccs_lock_t pending_lock = NULL;
+ cc_uint32 type = 0;
+
+ if (!io_lock_state) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ pending_lock = ccs_lock_array_object_at_index (io_lock_state->locks,
+ in_pending_lock_index);
+ if (!pending_lock || in_pending_lock_index < io_lock_state->first_pending_lock_index) {
+ err = cci_check_error (ccErrBadParam);
+ }
+ }
+
+ if (!err) {
+ err = ccs_lock_type (pending_lock, &type);
+ }
+
+ if (!err && (type == cc_lock_upgrade || type == cc_lock_downgrade)) {
+ /* lock upgrades or downgrades. Find the old lock and remove it. */
+ ccs_pipe_t pending_client_pipe = CCS_PIPE_NULL;
+
+ err = ccs_lock_client_pipe (pending_lock, &pending_client_pipe);
+
+ if (!err) {
+ cc_uint64 i;
+
+ for (i = 0; !err && i < io_lock_state->first_pending_lock_index; i++) {
+ ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i);
+ cc_uint32 is_lock_for_client = 0;
+
+ err = ccs_lock_is_for_client_pipe (lock, pending_client_pipe, &is_lock_for_client);
+
+ if (!err && is_lock_for_client) {
+ cci_debug_printf ("%s: Removing old lock %p at index %d to replace with pending lock %p.",
+ __FUNCTION__, lock, (int) i, pending_lock);
+ err = ccs_lock_status_remove_lock (io_lock_state, i);
+ if (!err) { i--; in_pending_lock_index--; /* We removed one so back up an index */ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (!err) {
+ cc_uint64 new_lock_index = 0;
+
+ err = ccs_lock_array_move (io_lock_state->locks,
+ in_pending_lock_index,
+ io_lock_state->first_pending_lock_index,
+ &new_lock_index);
+ if (!err) { io_lock_state->first_pending_lock_index++; }
+ }
+
+ if (!err) {
+ err = ccs_lock_grant_lock (pending_lock);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_state_check_pending_lock (ccs_lock_state_t io_lock_state,
+ ccs_pipe_t in_pending_lock_client_pipe,
+ cc_uint32 in_pending_lock_type,
+ cc_uint32 *out_grant_lock)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 is_write_locked = 0;
+ cc_uint32 client_has_lock = 0;
+ cc_uint32 other_clients_have_locks = 0;
+ cc_uint32 client_lock_type = 0;
+ cc_uint64 client_lock_index = 0;
+ cc_uint32 grant_lock = 0;
+
+ if (!io_lock_state ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_pending_lock_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!out_grant_lock ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_uint64 i;
+ cc_uint64 lock_count = io_lock_state->first_pending_lock_index;
+
+ for (i = 0; !err && i < lock_count; i++) {
+ ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i);
+ cc_uint32 lock_type = 0;
+ cc_uint32 lock_is_for_client = 0;
+
+ err = ccs_lock_type (lock, &lock_type);
+
+ if (!err) {
+ err = ccs_lock_is_for_client_pipe (lock, in_pending_lock_client_pipe,
+ &lock_is_for_client);
+ }
+
+ if (!err) {
+ if (lock_type == cc_lock_write || lock_type == cc_lock_upgrade) {
+ is_write_locked = 1;
+ }
+
+ if (!lock_is_for_client) {
+ other_clients_have_locks = 1;
+
+ } else if (!client_has_lock) { /* only record type of 1st lock */
+ client_has_lock = 1;
+ client_lock_type = lock_type;
+ client_lock_index = i;
+ }
+ }
+ }
+ }
+
+ if (!err) {
+ cc_uint64 lock_count = io_lock_state->first_pending_lock_index;
+
+ if (in_pending_lock_type == cc_lock_write) {
+ if (client_has_lock) {
+ err = cci_check_error (ccErrBadLockType);
+ } else {
+ grant_lock = (lock_count == 0);
+ }
+
+ } else if (in_pending_lock_type == cc_lock_read) {
+ if (client_has_lock) {
+ err = cci_check_error (ccErrBadLockType);
+ } else {
+ grant_lock = !is_write_locked;
+ }
+
+ } else if (in_pending_lock_type == cc_lock_upgrade) {
+ if (!client_has_lock || (client_lock_type != cc_lock_read &&
+ client_lock_type != cc_lock_downgrade)) {
+ err = cci_check_error (ccErrBadLockType);
+ } else {
+ /* don't grant if other clients have read locks */
+ grant_lock = !other_clients_have_locks;
+ }
+
+ } else if (in_pending_lock_type == cc_lock_downgrade) {
+ if (!client_has_lock || (client_lock_type != cc_lock_write &&
+ client_lock_type != cc_lock_upgrade)) {
+ err = cci_check_error (ccErrBadLockType);
+ } else {
+ /* downgrades can never block */
+ grant_lock = 1;
+ }
+ } else {
+ err = cci_check_error (ccErrBadLockType);
+ }
+ }
+
+ if (!err) {
+ *out_grant_lock = grant_lock;
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_lock_status_try_to_grant_pending_locks (ccs_lock_state_t io_lock_state)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 done = 0;
+
+ if (!io_lock_state) { err = cci_check_error (ccErrBadParam); }
+
+ /* Look at the pending locks and see if we can grant them.
+ * Note that downgrade locks mean we must check all pending locks each pass
+ * since a downgrade lock might be last in the list. */
+
+ while (!err && !done) {
+ cc_uint64 i;
+ cc_uint64 count = ccs_lock_array_count (io_lock_state->locks);
+ cc_uint32 granted_lock = 0;
+
+ for (i = io_lock_state->first_pending_lock_index; !err && i < count; i++) {
+ ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i);
+ cc_uint32 lock_type = 0;
+ ccs_pipe_t client_pipe = CCS_PIPE_NULL;
+ cc_uint32 can_grant_lock_now = 0;
+
+ err = ccs_lock_client_pipe (lock, &client_pipe);
+
+ if (!err) {
+ err = ccs_lock_type (lock, &lock_type);
+ }
+
+ if (!err) {
+ err = ccs_lock_state_check_pending_lock (io_lock_state, client_pipe,
+ lock_type, &can_grant_lock_now);
+ }
+
+ if (!err && can_grant_lock_now) {
+ err = ccs_lock_status_grant_lock (io_lock_state, i);
+ if (!err) { granted_lock = 1; }
+ }
+ }
+
+ if (!err && !granted_lock) {
+ /* we walked over all the locks and couldn't grant any of them */
+ done = 1;
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_state_add (ccs_lock_state_t io_lock_state,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ cc_uint32 in_lock_type,
+ cc_uint32 in_block,
+ cc_uint32 *out_will_send_reply)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 can_grant_lock_now = 0;
+
+ if (!io_lock_state ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_send_reply ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ /* Sanity check: if there are any pending locks for this client
+ * the client must have timed out waiting for our reply. Remove any
+ * existing pending locks for the client. */
+ cc_uint64 i;
+
+ for (i = io_lock_state->first_pending_lock_index; !err && i < ccs_lock_array_count (io_lock_state->locks); i++) {
+ ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i);
+ cc_uint32 has_pending_lock_for_client = 0;
+
+ err = ccs_lock_is_for_client_pipe (lock, in_client_pipe, &has_pending_lock_for_client);
+
+ if (!err && has_pending_lock_for_client) {
+ cci_debug_printf ("WARNING %s: Removing unexpected pending lock %p at index %d.",
+ __FUNCTION__, lock, (int) i);
+ err = ccs_lock_status_remove_lock (io_lock_state, i);
+ if (!err) { i--; /* We removed one so back up an index */ }
+ }
+ }
+ }
+
+ if (!err) {
+ err = ccs_lock_state_check_pending_lock (io_lock_state, in_client_pipe,
+ in_lock_type, &can_grant_lock_now);
+ }
+
+ if (!err) {
+ if (!can_grant_lock_now && (in_block == cc_lock_noblock)) {
+ err = cci_check_error (io_lock_state->pending_lock_err);
+
+ } else {
+ cc_uint64 new_lock_index = 0;
+
+ err = ccs_lock_status_add_pending_lock (io_lock_state,
+ in_client_pipe,
+ in_reply_pipe,
+ in_lock_type,
+ &new_lock_index);
+
+ if (!err && can_grant_lock_now) {
+ err = ccs_lock_status_grant_lock (io_lock_state, new_lock_index);
+
+ if (!err && (in_lock_type == cc_lock_downgrade)) {
+ /* downgrades can allow us to grant other locks */
+ err = ccs_lock_status_try_to_grant_pending_locks (io_lock_state);
+ }
+ }
+ }
+ }
+
+ if (!err) {
+ /* ccs_lock_state_add sends its replies via callback so caller shouldn't */
+ *out_will_send_reply = 1;
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_state_remove (ccs_lock_state_t io_lock_state,
+ ccs_pipe_t in_client_pipe)
+{
+ cc_int32 err = ccNoError;
+ cc_uint32 found_lock = 0;
+
+ if (!io_lock_state ) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_uint64 i;
+
+ /* Remove all locks for this client.
+ * There should only be one so warn if there are multiple */
+ for (i = 0; !err && i < io_lock_state->first_pending_lock_index; i++) {
+ ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i);
+ cc_uint32 is_for_client = 0;
+
+ err = ccs_lock_is_for_client_pipe (lock, in_client_pipe, &is_for_client);
+
+ if (!err && is_for_client) {
+ if (found_lock) {
+ cci_debug_printf ("WARNING %s: Found multiple locks for client.",
+ __FUNCTION__);
+ }
+
+ found_lock = 1;
+
+ cci_debug_printf ("%s: Removing lock %p at index %d.", __FUNCTION__, lock, (int) i);
+ err = ccs_lock_status_remove_lock (io_lock_state, i);
+ if (!err) { i--; /* We removed one so back up an index */ }
+ }
+ }
+ }
+
+ if (!err && !found_lock) {
+ err = cci_check_error (io_lock_state->no_lock_err);
+ }
+
+ if (!err) {
+ err = ccs_lock_status_try_to_grant_pending_locks (io_lock_state);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_lock_state_invalidate_lock (ccs_lock_state_t io_lock_state,
+ ccs_lock_t in_lock)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_lock_state) { err = ccErrBadParam; }
+
+ if (!err) {
+ cc_uint64 i;
+ cc_uint64 count = ccs_lock_array_count (io_lock_state->locks);
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_lock_t lock = ccs_lock_array_object_at_index (io_lock_state->locks, i);
+
+ if (lock == in_lock) {
+ err = ccs_lock_status_remove_lock (io_lock_state, i);
+
+ if (!err) {
+ err = ccs_lock_status_try_to_grant_pending_locks (io_lock_state);
+ break;
+ }
+ }
+ }
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/ccs_lock_state.h b/src/ccapi/server/ccs_lock_state.h
new file mode 100644
index 000000000000..de91fca40fc9
--- /dev/null
+++ b/src/ccapi/server/ccs_lock_state.h
@@ -0,0 +1,51 @@
+/* ccapi/server/ccs_lock_state.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_LOCK_STATE_H
+#define CCS_LOCK_STATE_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_lock_state_new (ccs_lock_state_t *out_lock_state,
+ cc_int32 in_invalid_object_err,
+ cc_int32 in_pending_lock_err,
+ cc_int32 in_no_lock_err);
+
+cc_int32 ccs_lock_state_release (ccs_lock_state_t io_lock_state);
+
+cc_int32 ccs_lock_state_add (ccs_lock_state_t io_lock_state,
+ ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ cc_uint32 in_lock_type,
+ cc_uint32 in_block,
+ cc_uint32 *out_will_send_reply);
+
+cc_int32 ccs_lock_state_remove (ccs_lock_state_t io_lock_state,
+ ccs_pipe_t in_client_pipe);
+
+cc_int32 ccs_lock_state_invalidate_lock (ccs_lock_state_t io_lock_state,
+ ccs_lock_t in_lock);
+
+#endif /* CCS_LOCK_STATE_H */
diff --git a/src/ccapi/server/ccs_os_notify.h b/src/ccapi/server/ccs_os_notify.h
new file mode 100644
index 000000000000..4021568f530b
--- /dev/null
+++ b/src/ccapi/server/ccs_os_notify.h
@@ -0,0 +1,37 @@
+/* ccapi/server/ccs_os_notify.h */
+/*
+ * Copyright 2006-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.
+ */
+
+#ifndef CCS_OS_NOTIFY_H
+#define CCS_OS_NOTIFY_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_os_notify_cache_collection_changed (ccs_cache_collection_t io_cache_collection);
+
+cc_int32 ccs_os_notify_ccache_changed (ccs_cache_collection_t io_cache_collection,
+ const char *in_ccache_name);
+
+
+#endif /* CCS_OS_NOTIFY_H */
diff --git a/src/ccapi/server/ccs_os_pipe.h b/src/ccapi/server/ccs_os_pipe.h
new file mode 100644
index 000000000000..4f6a379ceb7d
--- /dev/null
+++ b/src/ccapi/server/ccs_os_pipe.h
@@ -0,0 +1,42 @@
+/* ccapi/server/ccs_os_pipe.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_OS_PIPE_H
+#define CCS_OS_PIPE_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_os_pipe_valid (ccs_pipe_t in_pipe);
+
+cc_int32 ccs_os_pipe_compare (ccs_pipe_t in_pipe,
+ ccs_pipe_t in_compare_to_pipe,
+ cc_uint32 *out_equal);
+
+cc_int32 ccs_os_pipe_copy (ccs_pipe_t *out_pipe,
+ ccs_pipe_t in_pipe);
+
+cc_int32 ccs_os_pipe_release (ccs_pipe_t io_pipe);
+
+#endif /* CCS_OS_PIPE_H */
diff --git a/src/ccapi/server/ccs_os_server.h b/src/ccapi/server/ccs_os_server.h
new file mode 100644
index 000000000000..dc89f1d6dd3c
--- /dev/null
+++ b/src/ccapi/server/ccs_os_server.h
@@ -0,0 +1,40 @@
+/* ccapi/server/ccs_os_server.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_OS_SERVER_H
+#define CCS_OS_SERVER_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_os_server_initialize (int argc, const char *argv[]);
+
+cc_int32 ccs_os_server_cleanup (int argc, const char *argv[]);
+
+cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[]);
+
+cc_int32 ccs_os_server_send_reply (ccs_pipe_t in_reply_pipe,
+ k5_ipc_stream in_reply_stream);
+
+#endif /* CCS_OS_SERVER_H */
diff --git a/src/ccapi/server/ccs_pipe.c b/src/ccapi/server/ccs_pipe.c
new file mode 100644
index 000000000000..37744f6107d5
--- /dev/null
+++ b/src/ccapi/server/ccs_pipe.c
@@ -0,0 +1,58 @@
+/* ccapi/server/ccs_pipe.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+#include "ccs_os_pipe.h"
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_pipe_valid (ccs_pipe_t in_pipe)
+{
+ return ccs_os_pipe_valid (in_pipe);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_pipe_compare (ccs_pipe_t in_pipe,
+ ccs_pipe_t in_compare_to_pipe,
+ cc_uint32 *out_equal)
+{
+ return ccs_os_pipe_compare (in_pipe, in_compare_to_pipe, out_equal);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_pipe_copy (ccs_pipe_t *out_pipe,
+ ccs_pipe_t in_pipe)
+{
+ return ccs_os_pipe_copy (out_pipe, in_pipe);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_pipe_release (ccs_pipe_t io_pipe)
+{
+ return ccs_os_pipe_release (io_pipe);
+}
diff --git a/src/ccapi/server/ccs_pipe.h b/src/ccapi/server/ccs_pipe.h
new file mode 100644
index 000000000000..6e4f9efa48db
--- /dev/null
+++ b/src/ccapi/server/ccs_pipe.h
@@ -0,0 +1,42 @@
+/* ccapi/server/ccs_pipe.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_PIPE_H
+#define CCS_PIPE_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_pipe_valid (ccs_pipe_t in_pipe);
+
+cc_int32 ccs_pipe_compare (ccs_pipe_t in_pipe,
+ ccs_pipe_t in_compare_to_pipe,
+ cc_uint32 *out_equal);
+
+cc_int32 ccs_pipe_copy (ccs_pipe_t *out_pipe,
+ ccs_pipe_t in_pipe);
+
+cc_int32 ccs_pipe_release (ccs_pipe_t io_pipe);
+
+#endif /* CCS_PIPE_H */
diff --git a/src/ccapi/server/ccs_server.c b/src/ccapi/server/ccs_server.c
new file mode 100644
index 000000000000..1fc8d2c5e37f
--- /dev/null
+++ b/src/ccapi/server/ccs_server.c
@@ -0,0 +1,408 @@
+/* ccapi/server/ccs_server.c */
+/*
+ * Copyright 2006, 2007 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 "ccs_common.h"
+#include "ccs_os_server.h"
+
+/* Server Globals: */
+
+cci_uuid_string_t g_server_id = NULL;
+ccs_cache_collection_t g_cache_collection = NULL;
+ccs_client_array_t g_client_array = NULL;
+
+/* ------------------------------------------------------------------------ */
+
+int main (int argc, const char *argv[])
+{
+ cc_int32 err = 0;
+
+ if (!err) {
+ err = ccs_os_server_initialize (argc, argv);
+ }
+
+ if (!err) {
+ err = cci_identifier_new_uuid (&g_server_id);
+ }
+
+ if (!err) {
+ err = ccs_cache_collection_new (&g_cache_collection);
+ }
+
+ if (!err) {
+ err = ccs_client_array_new (&g_client_array);
+ }
+
+ if (!err) {
+ err = ccs_os_server_listen_loop (argc, argv);
+ }
+
+ if (!err) {
+ free (g_server_id);
+ cci_check_error (ccs_cache_collection_release (g_cache_collection));
+ cci_check_error (ccs_client_array_release (g_client_array));
+
+ err = ccs_os_server_cleanup (argc, argv);
+ }
+
+ return cci_check_error (err) ? 1 : 0;
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_new_identifier (cci_identifier_t *out_identifier)
+{
+ return cci_check_error (cci_identifier_new (out_identifier,
+ g_server_id));
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_add_client (ccs_pipe_t in_connection_pipe)
+{
+ cc_int32 err = ccNoError;
+ ccs_client_t client = NULL;
+
+ if (!err) {
+ err = ccs_client_new (&client, in_connection_pipe);
+ }
+
+ if (!err) {
+ cci_debug_printf ("%s: Adding client %p.", __FUNCTION__, client);
+ err = ccs_client_array_insert (g_client_array,
+ client,
+ ccs_client_array_count (g_client_array));
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_remove_client (ccs_pipe_t in_connection_pipe)
+{
+ cc_int32 err = ccNoError;
+
+ if (!err) {
+ cc_uint64 i;
+ cc_uint64 count = ccs_client_array_count (g_client_array);
+ cc_uint32 found = 0;
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_client_t client = ccs_client_array_object_at_index (g_client_array, i);
+
+ err = ccs_client_uses_pipe (client, in_connection_pipe, &found);
+
+ if (!err && found) {
+ cci_debug_printf ("%s: Removing client %p.", __FUNCTION__, client);
+ err = ccs_client_array_remove (g_client_array, i);
+ break;
+ }
+ }
+
+ if (!err && !found) {
+ cci_debug_printf ("WARNING %s() didn't find client in client list.",
+ __FUNCTION__);
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_client_for_pipe (ccs_pipe_t in_client_pipe,
+ ccs_client_t *out_client)
+{
+ cc_int32 err = ccNoError;
+ ccs_client_t client_for_pipe = NULL;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!out_client ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ cc_uint64 i;
+ cc_uint64 count = ccs_client_array_count (g_client_array);
+
+ for (i = 0; !err && i < count; i++) {
+ ccs_client_t client = ccs_client_array_object_at_index (g_client_array, i);
+ cc_uint32 uses_pipe = 0;
+
+ err = ccs_client_uses_pipe (client, in_client_pipe, &uses_pipe);
+
+ if (!err && uses_pipe) {
+ client_for_pipe = client;
+ break;
+ }
+ }
+ }
+
+ if (!err) {
+ *out_client = client_for_pipe; /* may be NULL if not found */
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_client_is_valid (ccs_pipe_t in_client_pipe,
+ cc_uint32 *out_client_is_valid)
+{
+ cc_int32 err = ccNoError;
+ ccs_client_t client = NULL;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!out_client_is_valid ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = ccs_server_client_for_pipe (in_client_pipe, &client);
+ }
+
+ if (!err) {
+ *out_client_is_valid = (client != NULL);
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static cc_int32 ccs_server_request_demux (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ ccs_cache_collection_t in_cache_collection,
+ enum cci_msg_id_t in_request_name,
+ cci_identifier_t in_request_identifier,
+ k5_ipc_stream in_request_data,
+ cc_uint32 *out_will_block,
+ k5_ipc_stream *out_reply_data)
+{
+ cc_int32 err = ccNoError;
+
+ if (!ccs_pipe_valid (in_reply_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
+ if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ if (in_request_name > cci_context_first_msg_id &&
+ in_request_name < cci_context_last_msg_id) {
+ /* Note: context identifier doesn't need to match.
+ * Client just uses the identifier to detect server relaunch. */
+
+ if (!err) {
+ err = ccs_cache_collection_handle_message (in_client_pipe,
+ in_reply_pipe,
+ in_cache_collection,
+ in_request_name,
+ in_request_data,
+ out_will_block,
+ out_reply_data);
+ }
+
+ } else if (in_request_name > cci_ccache_first_msg_id &&
+ in_request_name < cci_ccache_last_msg_id) {
+ ccs_ccache_t ccache = NULL;
+
+ err = ccs_cache_collection_find_ccache (in_cache_collection,
+ in_request_identifier,
+ &ccache);
+
+ if (!err) {
+ err = ccs_ccache_handle_message (in_client_pipe,
+ in_reply_pipe,
+ ccache,
+ in_cache_collection,
+ in_request_name,
+ in_request_data,
+ out_will_block,
+ out_reply_data);
+ }
+
+ } else if (in_request_name > cci_ccache_iterator_first_msg_id &&
+ in_request_name < cci_ccache_iterator_last_msg_id) {
+ ccs_ccache_iterator_t ccache_iterator = NULL;
+
+ err = ccs_cache_collection_find_ccache_iterator (in_cache_collection,
+ in_request_identifier,
+ &ccache_iterator);
+
+ if (!err) {
+ err = ccs_ccache_iterator_handle_message (ccache_iterator,
+ in_cache_collection,
+ in_request_name,
+ in_request_data,
+ out_reply_data);
+ }
+
+ if (!err) {
+ *out_will_block = 0; /* can't block */
+ }
+
+ } else if (in_request_name > cci_credentials_iterator_first_msg_id &&
+ in_request_name < cci_credentials_iterator_last_msg_id) {
+ ccs_credentials_iterator_t credentials_iterator = NULL;
+ ccs_ccache_t ccache = NULL;
+
+ err = ccs_cache_collection_find_credentials_iterator (in_cache_collection,
+ in_request_identifier,
+ &ccache,
+ &credentials_iterator);
+
+ if (!err) {
+ err = ccs_credentials_iterator_handle_message (credentials_iterator,
+ ccache,
+ in_request_name,
+ in_request_data,
+ out_reply_data);
+ }
+
+ if (!err) {
+ *out_will_block = 0; /* can't block */
+ }
+
+ } else {
+ err = ccErrBadInternalMessage;
+ }
+ }
+
+ return cci_check_error (err);
+}
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_handle_request (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ k5_ipc_stream in_request)
+{
+ cc_int32 err = ccNoError;
+ enum cci_msg_id_t request_name = 0;
+ cci_identifier_t request_identifier = NULL;
+ cc_uint32 will_block = 0;
+ k5_ipc_stream reply_data = NULL;
+
+ if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_request ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_message_read_request_header (in_request,
+ &request_name,
+ &request_identifier);
+ }
+
+ if (!err) {
+ cc_uint32 server_err = 0;
+ cc_uint32 valid = 0;
+ ccs_cache_collection_t cache_collection = g_cache_collection;
+
+ server_err = cci_identifier_is_for_server (request_identifier,
+ g_server_id,
+ &valid);
+
+ if (!server_err && !valid) {
+ server_err = cci_message_invalid_object_err (request_name);
+ }
+
+ if (!server_err) {
+
+ /* Monolithic server implementation would need to select
+ * cache collection here. Currently we only support per-user
+ * servers so we always use the same cache collection. */
+
+ server_err = ccs_server_request_demux (in_client_pipe,
+ in_reply_pipe,
+ cache_collection,
+ request_name,
+ request_identifier,
+ in_request,
+ &will_block,
+ &reply_data);
+ }
+
+ if (server_err || !will_block) {
+
+ /* send a reply now if the server isn't blocked on something */
+ err = ccs_server_send_reply (in_reply_pipe, server_err, reply_data);
+ }
+ }
+
+ cci_identifier_release (request_identifier);
+ krb5int_ipc_stream_release (reply_data);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_server_send_reply (ccs_pipe_t in_reply_pipe,
+ cc_int32 in_reply_err,
+ k5_ipc_stream in_reply_data)
+{
+ cc_int32 err = ccNoError;
+ k5_ipc_stream reply = NULL;
+
+ if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ err = cci_message_new_reply_header (&reply, in_reply_err);
+ }
+
+ if (!err && in_reply_data && krb5int_ipc_stream_size (in_reply_data) > 0) {
+ err = krb5int_ipc_stream_write (reply,
+ krb5int_ipc_stream_data (in_reply_data),
+ krb5int_ipc_stream_size (in_reply_data));
+ }
+
+ if (!err) {
+ err = ccs_os_server_send_reply (in_reply_pipe, reply);
+ }
+
+ krb5int_ipc_stream_release (reply);
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_uint64 ccs_server_client_count ()
+{
+ return ccs_client_array_count (g_client_array);
+}
diff --git a/src/ccapi/server/ccs_server.h b/src/ccapi/server/ccs_server.h
new file mode 100644
index 000000000000..e920ad9395df
--- /dev/null
+++ b/src/ccapi/server/ccs_server.h
@@ -0,0 +1,53 @@
+/* ccapi/server/ccs_server.h */
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef CCS_SERVER_H
+#define CCS_SERVER_H
+
+#include "ccs_types.h"
+
+cc_int32 ccs_server_new_identifier (cci_identifier_t *out_identifier);
+
+cc_int32 ccs_server_add_client (ccs_pipe_t in_connection_pipe);
+
+cc_int32 ccs_server_remove_client (ccs_pipe_t in_connection_pipe);
+
+cc_int32 ccs_server_client_for_pipe (ccs_pipe_t in_client_pipe,
+ ccs_client_t *out_client);
+
+cc_int32 ccs_server_client_is_valid (ccs_pipe_t in_client_pipe,
+ cc_uint32 *out_client_is_valid);
+
+cc_int32 ccs_server_handle_request (ccs_pipe_t in_client_pipe,
+ ccs_pipe_t in_reply_pipe,
+ k5_ipc_stream in_request);
+
+cc_int32 ccs_server_send_reply (ccs_pipe_t in_reply_pipe,
+ cc_int32 in_reply_err,
+ k5_ipc_stream in_reply_data);
+
+cc_uint64 ccs_server_client_count ();
+
+#endif /* CCS_SERVER_H */
diff --git a/src/ccapi/server/ccs_types.h b/src/ccapi/server/ccs_types.h
new file mode 100644
index 000000000000..773b3166e111
--- /dev/null
+++ b/src/ccapi/server/ccs_types.h
@@ -0,0 +1,120 @@
+/* ccapi/server/ccs_types.h */
+/*
+ * Copyright 2006, 2007 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.
+ */
+
+#ifndef CCS_TYPES_H
+#define CCS_TYPES_H
+
+#ifdef WIN32
+#pragma warning ( disable : 4068)
+#endif
+
+#include "cci_types.h"
+
+struct cci_array_d;
+
+typedef struct cci_array_d *ccs_client_array_t;
+
+typedef struct cci_array_d *ccs_callback_array_t;
+
+typedef struct cci_array_d *ccs_callbackref_array_t;
+
+typedef struct cci_array_d *ccs_iteratorref_array_t;
+
+typedef struct cci_array_d *ccs_lock_array_t;
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+/* ccs_os_pipe_t is IPC-specific so it's special cased here */
+
+#if TARGET_OS_MAC
+#include <mach/mach_types.h>
+typedef mach_port_t ccs_pipe_t; /* Mach IPC port */
+#define CCS_PIPE_NULL MACH_PORT_NULL
+
+#else
+
+#ifdef WIN32
+/* On Windows, a pipe is s struct: */
+#include "ccs_win_pipe.h"
+typedef struct ccs_win_pipe_t* ccs_pipe_t;
+#define CCS_PIPE_NULL (ccs_pipe_t)NULL
+
+#else
+typedef int ccs_pipe_t; /* Unix domain socket */
+#define CCS_PIPE_NULL -1
+
+#endif
+#endif
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+struct ccs_callback_d;
+typedef struct ccs_callback_d *ccs_callback_t;
+
+struct ccs_list_d;
+struct ccs_list_iterator_d;
+
+/* Used for iterator array invalidate function */
+typedef struct ccs_list_iterator_d *ccs_generic_list_iterator_t;
+
+typedef struct ccs_list_d *ccs_cache_collection_list_t;
+
+typedef struct ccs_list_d *ccs_ccache_list_t;
+typedef struct ccs_list_iterator_d *ccs_ccache_list_iterator_t;
+
+typedef struct ccs_list_d *ccs_credentials_list_t;
+typedef struct ccs_list_iterator_d *ccs_credentials_list_iterator_t;
+
+#ifdef TARGET_OS_MAC
+#pragma mark -
+#endif
+
+struct ccs_client_d;
+typedef struct ccs_client_d *ccs_client_t;
+
+struct ccs_lock_d;
+typedef struct ccs_lock_d *ccs_lock_t;
+
+struct ccs_lock_state_d;
+typedef struct ccs_lock_state_d *ccs_lock_state_t;
+
+struct ccs_credentials_d;
+typedef struct ccs_credentials_d *ccs_credentials_t;
+
+typedef ccs_credentials_list_iterator_t ccs_credentials_iterator_t;
+
+struct ccs_ccache_d;
+typedef struct ccs_ccache_d *ccs_ccache_t;
+
+typedef ccs_ccache_list_iterator_t ccs_ccache_iterator_t;
+
+struct ccs_cache_collection_d;
+typedef struct ccs_cache_collection_d *ccs_cache_collection_t;
+
+#endif /* CCS_TYPES_H */
diff --git a/src/ccapi/server/deps b/src/ccapi/server/deps
new file mode 100644
index 000000000000..31582f58db6d
--- /dev/null
+++ b/src/ccapi/server/deps
@@ -0,0 +1,170 @@
+#
+# Generated makefile dependencies follow.
+#
+ccs_array.so ccs_array.po $(OUTPRE)ccs_array.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_array_internal.h $(srcdir)/../common/cci_common.h \
+ $(srcdir)/../common/cci_cred_union.h $(srcdir)/../common/cci_debugging.h \
+ $(srcdir)/../common/cci_identifier.h $(srcdir)/../common/cci_message.h \
+ $(srcdir)/../common/cci_types.h ccs_array.c ccs_array.h \
+ ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.h \
+ ccs_credentials_iterator.h ccs_list.h ccs_lock.h ccs_lock_state.h \
+ ccs_pipe.h ccs_server.h ccs_types.h
+ccs_cache_collection.so ccs_cache_collection.po $(OUTPRE)ccs_cache_collection.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.c ccs_cache_collection.h \
+ ccs_callback.h ccs_ccache.h ccs_ccache_iterator.h ccs_client.h \
+ ccs_common.h ccs_credentials.h ccs_credentials_iterator.h \
+ ccs_list.h ccs_lock.h ccs_lock_state.h ccs_os_notify.h \
+ ccs_pipe.h ccs_server.h ccs_types.h
+ccs_callback.so ccs_callback.po $(OUTPRE)ccs_callback.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.c ccs_callback.h \
+ ccs_ccache.h ccs_ccache_iterator.h ccs_client.h ccs_common.h \
+ ccs_credentials.h ccs_credentials_iterator.h ccs_list.h \
+ ccs_lock.h ccs_lock_state.h ccs_pipe.h ccs_server.h \
+ ccs_types.h
+ccs_ccache.so ccs_ccache.po $(OUTPRE)ccs_ccache.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.c \
+ ccs_ccache.h ccs_ccache_iterator.h ccs_client.h ccs_common.h \
+ ccs_credentials.h ccs_credentials_iterator.h ccs_list.h \
+ ccs_lock.h ccs_lock_state.h ccs_os_notify.h ccs_pipe.h \
+ ccs_server.h ccs_types.h
+ccs_ccache_iterator.so ccs_ccache_iterator.po $(OUTPRE)ccs_ccache_iterator.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.c ccs_ccache_iterator.h ccs_client.h \
+ ccs_common.h ccs_credentials.h ccs_credentials_iterator.h \
+ ccs_list.h ccs_lock.h ccs_lock_state.h ccs_pipe.h ccs_server.h \
+ ccs_types.h
+ccs_client.so ccs_client.po $(OUTPRE)ccs_client.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.c ccs_client.h ccs_common.h \
+ ccs_credentials.h ccs_credentials_iterator.h ccs_list.h \
+ ccs_lock.h ccs_lock_state.h ccs_pipe.h ccs_server.h \
+ ccs_types.h
+ccs_credentials.so ccs_credentials.po $(OUTPRE)ccs_credentials.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.c \
+ ccs_credentials.h ccs_credentials_iterator.h ccs_list.h \
+ ccs_lock.h ccs_lock_state.h ccs_pipe.h ccs_server.h \
+ ccs_types.h
+ccs_credentials_iterator.so ccs_credentials_iterator.po \
+ $(OUTPRE)ccs_credentials_iterator.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.h \
+ ccs_credentials_iterator.c ccs_credentials_iterator.h \
+ ccs_list.h ccs_lock.h ccs_lock_state.h ccs_pipe.h ccs_server.h \
+ ccs_types.h
+ccs_list.so ccs_list.po $(OUTPRE)ccs_list.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_array_internal.h $(srcdir)/../common/cci_common.h \
+ $(srcdir)/../common/cci_cred_union.h $(srcdir)/../common/cci_debugging.h \
+ $(srcdir)/../common/cci_identifier.h $(srcdir)/../common/cci_message.h \
+ $(srcdir)/../common/cci_types.h ccs_array.h ccs_cache_collection.h \
+ ccs_callback.h ccs_ccache.h ccs_ccache_iterator.h ccs_client.h \
+ ccs_common.h ccs_credentials.h ccs_credentials_iterator.h \
+ ccs_list.c ccs_list.h ccs_list_internal.h ccs_lock.h \
+ ccs_lock_state.h ccs_pipe.h ccs_server.h ccs_types.h
+ccs_list_internal.so ccs_list_internal.po $(OUTPRE)ccs_list_internal.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_array_internal.h $(srcdir)/../common/cci_common.h \
+ $(srcdir)/../common/cci_cred_union.h $(srcdir)/../common/cci_debugging.h \
+ $(srcdir)/../common/cci_identifier.h $(srcdir)/../common/cci_message.h \
+ $(srcdir)/../common/cci_types.h ccs_array.h ccs_cache_collection.h \
+ ccs_callback.h ccs_ccache.h ccs_ccache_iterator.h ccs_client.h \
+ ccs_common.h ccs_credentials.h ccs_credentials_iterator.h \
+ ccs_list.h ccs_list_internal.c ccs_list_internal.h \
+ ccs_lock.h ccs_lock_state.h ccs_pipe.h ccs_server.h \
+ ccs_types.h
+ccs_lock.so ccs_lock.po $(OUTPRE)ccs_lock.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.h \
+ ccs_credentials_iterator.h ccs_list.h ccs_lock.c ccs_lock.h \
+ ccs_lock_state.h ccs_pipe.h ccs_server.h ccs_types.h
+ccs_lock_state.so ccs_lock_state.po $(OUTPRE)ccs_lock_state.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.h \
+ ccs_credentials_iterator.h ccs_list.h ccs_lock.h ccs_lock_state.c \
+ ccs_lock_state.h ccs_pipe.h ccs_server.h ccs_types.h
+ccs_pipe.so ccs_pipe.po $(OUTPRE)ccs_pipe.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.h \
+ ccs_credentials_iterator.h ccs_list.h ccs_lock.h ccs_lock_state.h \
+ ccs_os_pipe.h ccs_pipe.c ccs_pipe.h ccs_server.h ccs_types.h
+ccs_server.so ccs_server.po $(OUTPRE)ccs_server.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(COM_ERR_DEPS) $(top_srcdir)/include/CredentialsCache.h \
+ $(top_srcdir)/include/CredentialsCache2.h $(top_srcdir)/include/k5-ipc_stream.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(srcdir)/../common/cci_common.h $(srcdir)/../common/cci_cred_union.h \
+ $(srcdir)/../common/cci_debugging.h $(srcdir)/../common/cci_identifier.h \
+ $(srcdir)/../common/cci_message.h $(srcdir)/../common/cci_types.h \
+ ccs_array.h ccs_cache_collection.h ccs_callback.h ccs_ccache.h \
+ ccs_ccache_iterator.h ccs_client.h ccs_common.h ccs_credentials.h \
+ ccs_credentials_iterator.h ccs_list.h ccs_lock.h ccs_lock_state.h \
+ ccs_os_server.h ccs_pipe.h ccs_server.c ccs_server.h \
+ ccs_types.h
diff --git a/src/ccapi/server/mac/CCacheServerInfo.plist b/src/ccapi/server/mac/CCacheServerInfo.plist
new file mode 100644
index 000000000000..e03d5f3ffaf1
--- /dev/null
+++ b/src/ccapi/server/mac/CCacheServerInfo.plist
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>CCacheServer</string>
+ <key>CFBundleGetInfoString</key>
+ <string>4.1</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>edu.mit.Kerberos.CCacheServer</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>Kerberos Credentials Cache Server</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>CCSa</string>
+ <key>CFBundleVersion</key>
+ <string>0.0.1d1</string>
+ <key>CFBundleShortVersionString</key>
+ <string>5.5</string>
+ <key>CFBundleGetInfoString</key>
+ <string>5.5 Copyright MIT</string>
+ <key>KfMDisplayVersion</key>
+ <string>5.5 Copyright MIT</string>
+ <key>KfMDisplayCopyright</key>
+ <string>Copyright MIT</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>5.5 Copyright MIT</string>
+ <key>LSBackgroundOnly</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/src/ccapi/server/mac/ccs_os_notify.c b/src/ccapi/server/mac/ccs_os_notify.c
new file mode 100644
index 000000000000..e758deb5c9eb
--- /dev/null
+++ b/src/ccapi/server/mac/ccs_os_notify.c
@@ -0,0 +1,79 @@
+/* ccapi/server/mac/ccs_os_notify.c */
+/*
+ * Copyright 2006-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 "ccs_common.h"
+#include "ccs_os_notify.h"
+#include <CoreFoundation/CoreFoundation.h>
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_notify_cache_collection_changed (ccs_cache_collection_t io_cache_collection)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter ();
+
+ if (center) {
+ CFNotificationCenterPostNotification (center,
+ kCCAPICacheCollectionChangedNotification,
+ NULL, NULL, TRUE);
+ }
+ }
+
+
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_notify_ccache_changed (ccs_cache_collection_t io_cache_collection,
+ const char *in_ccache_name)
+{
+ cc_int32 err = ccNoError;
+
+ if (!io_cache_collection) { err = cci_check_error (ccErrBadParam); }
+ if (!in_ccache_name ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter ();
+ CFStringRef name = CFStringCreateWithCString (kCFAllocatorDefault,
+ in_ccache_name,
+ kCFStringEncodingUTF8);
+
+ if (center && name) {
+ CFNotificationCenterPostNotification (center,
+ kCCAPICCacheChangedNotification,
+ name, NULL, TRUE);
+ }
+
+ if (name) { CFRelease (name); }
+ }
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/mac/ccs_os_pipe.c b/src/ccapi/server/mac/ccs_os_pipe.c
new file mode 100644
index 000000000000..67f90307a230
--- /dev/null
+++ b/src/ccapi/server/mac/ccs_os_pipe.c
@@ -0,0 +1,79 @@
+/* ccapi/server/mac/ccs_os_pipe.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+#include "ccs_os_pipe.h"
+#include <mach/port.h>
+
+/* On Mac OS X ccs_pipe_t is a mach_port_t */
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_valid (ccs_pipe_t in_pipe)
+{
+ return MACH_PORT_VALID (in_pipe);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_compare (ccs_pipe_t in_pipe,
+ ccs_pipe_t in_compare_to_pipe,
+ cc_uint32 *out_equal)
+{
+ cc_int32 err = ccNoError;
+
+ if (!in_pipe ) { err = cci_check_error (ccErrBadParam); }
+ if (!in_compare_to_pipe) { err = cci_check_error (ccErrBadParam); }
+ if (!out_equal ) { err = cci_check_error (ccErrBadParam); }
+
+ if (!err) {
+ *out_equal = (in_pipe == in_compare_to_pipe);
+ }
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_copy (ccs_pipe_t *out_pipe,
+ ccs_pipe_t in_pipe)
+{
+ cc_int32 err = 0;
+
+ *out_pipe = in_pipe;
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_release (ccs_pipe_t io_pipe)
+{
+ cc_int32 err = 0;
+
+ /* Nothing to do here on Mac OS X */
+
+ return cci_check_error (err);
+}
diff --git a/src/ccapi/server/mac/ccs_os_server.c b/src/ccapi/server/mac/ccs_os_server.c
new file mode 100644
index 000000000000..b16f5e088cd2
--- /dev/null
+++ b/src/ccapi/server/mac/ccs_os_server.c
@@ -0,0 +1,97 @@
+/* ccapi/server/mac/ccs_os_server.c */
+/*
+ * Copyright 2006 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 "ccs_common.h"
+
+#include <syslog.h>
+#include "k5_mig_server.h"
+#include "ccs_os_server.h"
+
+/* ------------------------------------------------------------------------ */
+
+int32_t k5_ipc_server_add_client (mach_port_t in_client_port)
+{
+ return cci_check_error (ccs_server_add_client (in_client_port));
+}
+
+/* ------------------------------------------------------------------------ */
+
+int32_t k5_ipc_server_remove_client (mach_port_t in_client_port)
+{
+ return cci_check_error (ccs_server_remove_client (in_client_port));
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t k5_ipc_server_handle_request (mach_port_t in_connection_port,
+ mach_port_t in_reply_port,
+ k5_ipc_stream in_request_stream)
+{
+ return cci_check_error (ccs_server_handle_request (in_connection_port,
+ in_reply_port,
+ in_request_stream));
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_server_initialize (int argc, const char *argv[])
+{
+ cc_int32 err = 0;
+
+ openlog (argv[0], LOG_CONS | LOG_PID, LOG_AUTH);
+ syslog (LOG_INFO, "Starting up.");
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_server_cleanup (int argc, const char *argv[])
+{
+ cc_int32 err = 0;
+
+ syslog (LOG_NOTICE, "Exiting.");
+
+ return cci_check_error (err);
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[])
+{
+ return cci_check_error (k5_ipc_server_listen_loop ());
+}
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_server_send_reply (ccs_pipe_t in_reply_pipe,
+ k5_ipc_stream in_reply_stream)
+{
+ return cci_check_error (k5_ipc_server_send_reply (in_reply_pipe,
+ in_reply_stream));
+}
diff --git a/src/ccapi/server/mac/edu.mit.Kerberos.CCacheServer.plist b/src/ccapi/server/mac/edu.mit.Kerberos.CCacheServer.plist
new file mode 100644
index 000000000000..34e697cb06eb
--- /dev/null
+++ b/src/ccapi/server/mac/edu.mit.Kerberos.CCacheServer.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>edu.mit.Kerberos.CCacheServer</string>
+ <key>LimitLoadToSessionType</key>
+ <string>Background</string>
+ <key>Program</key>
+ <string>/System/Library/CoreServices/CCacheServer.app/Contents/MacOS/CCacheServer</string>
+ <key>MachServices</key>
+ <dict>
+ <key>edu.mit.Kerberos.CCacheServer.ipcLookup</key>
+ <dict>
+ <key>HideUntilCheckIn</key>
+ <true/>
+ <key>ResetAtClose</key>
+ <true/>
+ </dict>
+ <key>edu.mit.Kerberos.CCacheServer.ipcService</key>
+ <true/>
+ </dict>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>OnDemand</key>
+ <true/>
+ <key>ThrottleInterval</key>
+ <integer>0</integer>
+ <key>EnvironmentVariables</key>
+ <dict>
+ <key>CFFIXED_USER_HOME</key>
+ <string>/var/empty</string>
+ </dict>
+</dict>
+</plist>
diff --git a/src/ccapi/server/unix/Makefile.in b/src/ccapi/server/unix/Makefile.in
new file mode 100644
index 000000000000..b3743f06a8ac
--- /dev/null
+++ b/src/ccapi/server/unix/Makefile.in
@@ -0,0 +1,12 @@
+mydir=ccapi$(S)server$(S)unix
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+STLIBOBJS=
+OBJS=
+SRCS=
+
+all-unix: all-libobjs
+clean-unix:: clean-libobjs
+
+@libobj_frag@
+
diff --git a/src/ccapi/server/unix/deps b/src/ccapi/server/unix/deps
new file mode 100644
index 000000000000..2feac3c9d388
--- /dev/null
+++ b/src/ccapi/server/unix/deps
@@ -0,0 +1 @@
+# No dependencies here.
diff --git a/src/ccapi/server/win/Makefile.in b/src/ccapi/server/win/Makefile.in
new file mode 100644
index 000000000000..1c925a287f8e
--- /dev/null
+++ b/src/ccapi/server/win/Makefile.in
@@ -0,0 +1,114 @@
+# 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
+
+VERSIONRC = $(BUILDTOP)\..\windows\version.rc
+CCAPISERVERRES = $(OUTPRE)ccapiserver.res
+$(CCAPISERVERRES): $(VERSIONRC)
+ $(RC) $(RCFLAGS) -DCCAPISERVER_APP -fo $@ -r $**
+
+$(OUTPRE)ccapiserver.exe: $(OBJS) $(CCAPISERVERRES)
+ $(LINK) $(LFLAGS) /map:$*.map /out:$@ $(OBJS) $(LIBS) $(CCAPISERVERRES) $(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) rmdir /s /q $(SRCTMP)
diff --git a/src/ccapi/server/win/Server.sln b/src/ccapi/server/win/Server.sln
new file mode 100644
index 000000000000..ea1bd455f661
--- /dev/null
+++ b/src/ccapi/server/win/Server.sln
@@ -0,0 +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
diff --git a/src/ccapi/server/win/Server.vcproj b/src/ccapi/server/win/Server.vcproj
new file mode 100644
index 000000000000..626c7a3c789f
--- /dev/null
+++ b/src/ccapi/server/win/Server.vcproj
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Server"
+ ProjectGUID="{114DCD80-6D13-4AAA-9510-B51CE6D94C1C}"
+ RootNamespace="Server"
+ Keyword="MakeFileProj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="nmake"
+ ReBuildCommandLine="nmake"
+ CleanCommandLine="nmake clean"
+ Output=""
+ PreprocessorDefinitions="WIN32;_DEBUG;"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="nmake"
+ ReBuildCommandLine="nmake"
+ CleanCommandLine="nmake clean"
+ Output=""
+ PreprocessorDefinitions="WIN32;NDEBUG;"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\common\cci_debugging.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\cci_os_debugging.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\cci_stream.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_reply.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_request.h"
+ >
+ </File>
+ <File
+ RelativePath="..\ccs_server.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\ccutils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\init.hxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\include\k5-platform.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\secure.hxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\util.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\win-utils.h"
+ >
+ </File>
+ <File
+ RelativePath=".\workitem.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WorkQueue.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\common\cci_debugging.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\cci_os_debugging.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\cci_stream.c"
+ >
+ </File>
+ <File
+ RelativePath="..\ccs_lock.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_os_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_os_server.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccs_reply.Idl"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_reply_c.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_reply_s.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccs_request.idl"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_request_c.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_request_proc.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ccs_request_s.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\ccs_server.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\ccutils.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\init.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\secure.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\ccutil\util.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\win\win-utils.c"
+ >
+ </File>
+ <File
+ RelativePath=".\WorkItem.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\WorkQueue.cpp"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\..\common\win\ccs_reply.Acf"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/ccapi/server/win/WorkItem.cpp b/src/ccapi/server/win/WorkItem.cpp
new file mode 100644
index 000000000000..79a348737db3
--- /dev/null
+++ b/src/ccapi/server/win/WorkItem.cpp
@@ -0,0 +1,142 @@
+/*
+ * $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 <string.h>
+#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::initialize() {
+ hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ return 0;
+ }
+
+int WorkList::cleanup() {
+ CloseHandle(hEvent);
+ hEvent = INVALID_HANDLE_VALUE;
+ return 0;
+ }
+
+void WorkList::wait() {
+ WaitForSingleObject(hEvent, INFINITE);
+ }
+
+int WorkList::add(WorkItem* item) {
+ EnterCriticalSection(&cs);
+ wl.push_front(item);
+ LeaveCriticalSection(&cs);
+ SetEvent(hEvent);
+ 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
new file mode 100644
index 000000000000..fc5fa7e15079
--- /dev/null
+++ b/src/ccapi/server/win/WorkQueue.cpp
@@ -0,0 +1,74 @@
+/*
+ * $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 "WorkQueue.h"
+extern "C" {
+ #include "cci_debugging.h"
+ }
+
+#include "WorkItem.h"
+
+WorkList worklist;
+
+EXTERN_C int worklist_initialize() {
+ return worklist.initialize();
+ }
+
+EXTERN_C int worklist_cleanup() {
+ return worklist.cleanup();
+ }
+
+EXTERN_C void worklist_wait() {
+ worklist.wait();
+ }
+
+/* C interfaces: */
+EXTERN_C BOOL worklist_isEmpty() {
+ return worklist.isEmpty() ? TRUE : FALSE;
+ }
+
+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/WorkQueue.h b/src/ccapi/server/win/WorkQueue.h
new file mode 100644
index 000000000000..68aa8b1cacdd
--- /dev/null
+++ b/src/ccapi/server/win/WorkQueue.h
@@ -0,0 +1,51 @@
+/* ccapi/server/win/WorkQueue.h */
+/*
+ * Copyright 2007 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.
+ */
+
+#ifndef _work_queue_h
+#define _work_queue_h
+
+#include "windows.h"
+#include "ccs_pipe.h"
+
+EXTERN_C int worklist_initialize();
+
+EXTERN_C int worklist_cleanup();
+
+/* Wait for work to be added to the list (via worklist_add) from another thread */
+EXTERN_C void worklist_wait();
+
+EXTERN_C BOOL worklist_isEmpty();
+
+EXTERN_C int worklist_add( const long rpcmsg,
+ const ccs_pipe_t pipe,
+ const k5_ipc_stream stream,
+ const time_t serverStartTime);
+
+EXTERN_C int worklist_remove(long* rpcmsg,
+ ccs_pipe_t* pipe,
+ k5_ipc_stream* stream,
+ time_t* serverStartTime);
+
+#endif // _work_queue_h
diff --git a/src/ccapi/server/win/ccs_os_pipe.c b/src/ccapi/server/win/ccs_os_pipe.c
new file mode 100644
index 000000000000..7e190cee7c80
--- /dev/null
+++ b/src/ccapi/server/win/ccs_os_pipe.c
@@ -0,0 +1,62 @@
+/* ccapi/server/win/ccs_os_pipe.c */
+/*
+ * 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 "ccs_common.h"
+#include "ccs_os_pipe.h"
+#include "ccs_win_pipe.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* On Windows, a pipe is a struct. See ccs_win_pipe.h for details. */
+
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_valid (ccs_pipe_t in_pipe) {
+ return ccs_win_pipe_valid(in_pipe);
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_copy (ccs_pipe_t* out_pipe, ccs_pipe_t in_pipe) {
+ return ccs_win_pipe_copy(
+ out_pipe,
+ in_pipe);
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_release (ccs_pipe_t io_pipe) {
+ return ccs_win_pipe_release(io_pipe);
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_os_pipe_compare (ccs_pipe_t pipe_1,
+ ccs_pipe_t pipe_2,
+ cc_uint32 *out_equal) {
+
+ return ccs_win_pipe_compare(pipe_1, pipe_2, out_equal);
+ }
diff --git a/src/ccapi/server/win/ccs_os_server.cpp b/src/ccapi/server/win/ccs_os_server.cpp
new file mode 100644
index 000000000000..f84239491dac
--- /dev/null
+++ b/src/ccapi/server/win/ccs_os_server.cpp
@@ -0,0 +1,971 @@
+/*
+ * $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) {
+ err = worklist_initialize();
+ }
+
+ 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]);
+
+ worklist_cleanup();
+
+ 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;
+
+ ParseOpts::Opts opts = { 0 };
+ ParseOpts PO;
+ BOOL bQuitIfNoClients = FALSE;
+
+ 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;
+ /// TODO: check for NULL handle, error, etc. probably move to initialize func...
+ threadStatus = _beginthread(receiveLoop, 0, (void*)&rpcargs);
+
+ /* We handle the queue entries here. Work loop: */
+ while (ccs_server_client_count() > 0 || !bQuitIfNoClients) {
+ worklist_wait();
+ while (!worklist_isEmpty()) {
+ 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;
+ case CCMSG_QUIT:
+ bQuitIfNoClients = TRUE;
+ 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);
+ UINT64 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);
+ }
+
+ // tell main thread to shutdown since it won't receive any more messages
+ worklist_add(CCMSG_QUIT, NULL, NULL, 0);
+ _endthread();
+ } // End receiveLoop
+
+
+#if 0
+
+ return status;
+}
+#endif
+
+
+
+/* ------------------------------------------------------------------------ */
+/* The connection listener thread waits forever for a call to the CCAPI_CLIENT_<UUID>
+ 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);
+ UINT64 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;
+}
diff --git a/src/ccapi/server/win/ccs_request_proc.c b/src/ccapi/server/win/ccs_request_proc.c
new file mode 100644
index 000000000000..461c441edc18
--- /dev/null
+++ b/src/ccapi/server/win/ccs_request_proc.c
@@ -0,0 +1,114 @@
+/* ccapi/server/win/ccs_request_proc.c */
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+#include "ccs_request.h" // header file generated by MIDL compiler
+#include "cci_debugging.h"
+#include "WorkQueue.h"
+#include "win-utils.h"
+#include "ccs_win_pipe.h"
+
+void ccs_rpc_request(
+ const long rpcmsg, /* Message type */
+ const char tspHandle[], /* Client's tspdata* */
+ const char* pszUUID, /* Where client will listen for the reply */
+ const long lenRequest, /* Length of buffer */
+ const char pbRequest[], /* Data buffer */
+ const long serverStartTime, /* Which server session we're talking to */
+ long* return_status ) { /* Return code */
+
+ cc_int32 status = 0;
+ k5_ipc_stream stream;
+ UINT64* p = (UINT64*)(tspHandle);
+ WIN_PIPE* pipe = NULL;
+#if 0
+ cci_debug_printf("%s rpcmsg:%d; UUID:<%s> SST:<%s>", __FUNCTION__, rpcmsg, pszUUID, serverStartTime);
+#endif
+ status = (rpcmsg != CCMSG_REQUEST) && (rpcmsg != CCMSG_PING);
+
+ if (!status) {
+ status = krb5int_ipc_stream_new (&stream); /* Create a stream for the request data */
+ }
+
+ if (!status) { /* Put the data into the stream */
+ status = krb5int_ipc_stream_write (stream, pbRequest, lenRequest);
+ }
+
+ pipe = ccs_win_pipe_new(pszUUID, *p);
+ worklist_add(rpcmsg, pipe, stream, serverStartTime);
+ *return_status = status;
+ }
+
+
+void ccs_rpc_connect(
+ const long rpcmsg, /* Message type */
+ const char tspHandle[], /* Client's tspdata* */
+ const char* pszUUID, /* Data buffer */
+ long* return_status ) { /* Return code */
+
+ UINT64* p = (UINT64*)(tspHandle);
+ WIN_PIPE* pipe = ccs_win_pipe_new(pszUUID, *p);
+#if 0
+ cci_debug_printf("%s; rpcmsg:%d; UUID: <%s>", __FUNCTION__, rpcmsg, pszUUID);
+#endif
+ worklist_add( rpcmsg,
+ pipe,
+ NULL, /* No payload with connect request */
+ (const time_t)0 ); /* No server session number with connect request */
+ }
+
+
+// 'Authentication' is client setting a value in a file and the server
+// returning that value plus one.
+CC_UINT32 ccs_authenticate(const CC_CHAR* name) {
+ HANDLE hMap = 0;
+ PDWORD pvalue = 0;
+ CC_UINT32 result = 0;
+ DWORD status = 0;
+#if 0
+ cci_debug_printf("%s ( %s )", __FUNCTION__, name);
+#endif
+ hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, (LPSTR)name);
+ status = !hMap;
+
+ if (!status) {
+ pvalue = (PDWORD)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
+ status = !pvalue;
+ }
+
+ if (!status) {
+ *pvalue += 1;
+ result = *pvalue;
+ }
+
+ if (pvalue) {
+ UnmapViewOfFile(pvalue);
+ }
+
+ if (hMap) CloseHandle(hMap);
+ return result;
+ }
diff --git a/src/ccapi/server/win/ccs_win_pipe.c b/src/ccapi/server/win/ccs_win_pipe.c
new file mode 100644
index 000000000000..d23e4448e0a8
--- /dev/null
+++ b/src/ccapi/server/win/ccs_win_pipe.c
@@ -0,0 +1,164 @@
+/* ccapi/server/win/ccs_win_pipe.c */
+/*
+ * 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 "assert.h"
+#include <stdlib.h>
+#include <malloc.h>
+
+#include "ccs_win_pipe.h"
+#include "cci_debugging.h"
+
+/* Ref:
+struct ccs_win_pipe_t {
+ char* uuid;
+ UINT64 clientHandle;
+ }
+ */
+
+/* ------------------------------------------------------------------------ */
+
+struct ccs_win_pipe_t* ccs_win_pipe_new (const char* uuid, const UINT64 h) {
+
+ cc_int32 err = ccNoError;
+ struct ccs_win_pipe_t* out_pipe = NULL;
+ char* uuidCopy = NULL;
+
+ if (!err) {
+ if (!uuid) {err = cci_check_error(ccErrBadParam);}
+ }
+
+ if (!err) {
+ uuidCopy = (char*)malloc(1+strlen(uuid));
+ if (!uuidCopy) {err = cci_check_error(ccErrBadParam);}
+ strcpy(uuidCopy, uuid);
+ }
+
+ if (!err) {
+ out_pipe = (struct ccs_win_pipe_t*)malloc(sizeof(struct ccs_win_pipe_t));
+ if (!out_pipe) {err = cci_check_error(ccErrBadParam);}
+ out_pipe->uuid = uuidCopy;
+ out_pipe->clientHandle = h;
+ }
+#if 0
+ cci_debug_printf("0x%X = %s(%s, 0x%X)", out_pipe, __FUNCTION__, uuid, h);
+#endif
+ return out_pipe;
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_win_pipe_copy (WIN_PIPE** out_pipe,
+ const WIN_PIPE* in_pipe) {
+
+ *out_pipe =
+ ccs_win_pipe_new(
+ ccs_win_pipe_getUuid (in_pipe),
+ ccs_win_pipe_getHandle(in_pipe) );
+
+ return (*out_pipe) ? ccNoError : ccErrBadParam;
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_win_pipe_release(const WIN_PIPE* in_pipe) {
+
+ cc_int32 err = ccNoError;
+
+ if (!ccs_win_pipe_valid(in_pipe)) {err = cci_check_error(ccErrBadParam);}
+
+ if (!err) {
+ if (!in_pipe->uuid) free(in_pipe->uuid);
+ if (!in_pipe) free(in_pipe);
+ }
+
+ return err;
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_win_pipe_valid (const WIN_PIPE* in_pipe) {
+
+ if (!in_pipe) {
+ cci_check_error(ccErrBadParam);
+ return FALSE;
+ }
+
+ if (!in_pipe->uuid) {
+ cci_check_error(ccErrBadParam);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+/* ------------------------------------------------------------------------ */
+
+cc_int32 ccs_win_pipe_compare (const WIN_PIPE* in_pipe_1,
+ const WIN_PIPE* in_pipe_2,
+ cc_uint32 *out_equal) {
+
+ cc_int32 err = ccNoError;
+ int seq = 0;
+ *out_equal = FALSE;
+
+ if (!ccs_win_pipe_valid(in_pipe_1)) {err = cci_check_error(ccErrBadParam);}
+ if (!ccs_win_pipe_valid(in_pipe_2)) {err = cci_check_error(ccErrBadParam);}
+ if (!out_equal) {err = cci_check_error(ccErrBadParam);}
+
+ /* A disconnect doesn't have a tls* with it -- only the uuid. SO only
+ compare the uuids.
+ */
+ if (!err) {
+ seq = strcmp( ccs_win_pipe_getUuid(in_pipe_1),
+ ccs_win_pipe_getUuid(in_pipe_2) );
+ *out_equal = (seq == 0);
+ }
+
+ return err;
+ }
+
+/* ------------------------------------------------------------------------ */
+
+char* ccs_win_pipe_getUuid (const WIN_PIPE* in_pipe) {
+
+ char* result = NULL;
+
+ if (!ccs_win_pipe_valid(in_pipe)) {cci_check_error(ccErrBadParam);}
+ else {result = in_pipe->uuid;}
+
+ return result;
+ }
+
+/* ------------------------------------------------------------------------ */
+
+UINT64 ccs_win_pipe_getHandle (const WIN_PIPE* in_pipe) {
+
+ UINT64 result = 0;
+
+ if (!ccs_win_pipe_valid(in_pipe)) {cci_check_error(ccErrBadParam);}
+ else {result = in_pipe->clientHandle;}
+
+ return result;
+ }
diff --git a/src/ccapi/server/win/ccs_win_pipe.h b/src/ccapi/server/win/ccs_win_pipe.h
new file mode 100644
index 000000000000..fef99953539b
--- /dev/null
+++ b/src/ccapi/server/win/ccs_win_pipe.h
@@ -0,0 +1,68 @@
+/* ccapi/server/win/ccs_win_pipe.h */
+/*
+ * 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.
+ */
+
+#ifndef _ccs_win_pipe_h_
+#define _ccs_win_pipe_h_
+
+#include "windows.h"
+
+#include "CredentialsCache.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* On Windows, a pipe is a struct containing a UUID and a handle. Both the
+ UUID and handle are supplied by the client.
+
+ The UUID is used to build the client's reply endpoint.
+
+ The handle is to the requesting client thread's thread local storage struct,
+ so that the client's one and only reply handler can put reply data where
+ the requesting thread will be able to see it.
+ */
+
+struct ccs_win_pipe_t {
+ char* uuid;
+ UINT64 clientHandle;
+ };
+
+typedef struct ccs_win_pipe_t WIN_PIPE;
+
+struct ccs_win_pipe_t* ccs_win_pipe_new(const char* uuid, const UINT64 h);
+
+cc_int32 ccs_win_pipe_release (const WIN_PIPE* io_pipe);
+
+cc_int32 ccs_win_pipe_compare (const WIN_PIPE* win_pipe_1,
+ const WIN_PIPE* win_pipe_2,
+ cc_uint32 *out_equal);
+
+cc_int32 ccs_win_pipe_copy (WIN_PIPE** out_pipe,
+ const WIN_PIPE* in_pipe);
+
+cc_int32 ccs_win_pipe_valid (const WIN_PIPE* in_pipe);
+
+char* ccs_win_pipe_getUuid (const WIN_PIPE* in_pipe);
+UINT64 ccs_win_pipe_getHandle (const WIN_PIPE* in_pipe);
+
+#endif // _ccs_win_pipe_h_
diff --git a/src/ccapi/server/win/workitem.h b/src/ccapi/server/win/workitem.h
new file mode 100644
index 000000000000..fff56f32643f
--- /dev/null
+++ b/src/ccapi/server/win/workitem.h
@@ -0,0 +1,51 @@
+#ifndef __WorkItem
+#define __WorkItem
+
+#include <list>
+#include "windows.h"
+
+extern "C" {
+ #include "ccs_pipe.h"
+ }
+
+class WorkItem {
+private:
+ k5_ipc_stream _buf;
+ WIN_PIPE* _pipe;
+ const long _rpcmsg;
+ const long _sst;
+public:
+ WorkItem( k5_ipc_stream buf,
+ WIN_PIPE* pipe,
+ const long type,
+ const long serverStartTime);
+ WorkItem( const WorkItem&);
+ WorkItem();
+ ~WorkItem();
+
+ const k5_ipc_stream payload() const {return _buf;}
+ const k5_ipc_stream take_payload();
+ WIN_PIPE* take_pipe();
+ WIN_PIPE* pipe() const {return _pipe;}
+ const long type() const {return _rpcmsg;}
+ const long sst() const {return _sst;}
+ char* print(char* buf);
+ };
+
+class WorkList {
+private:
+ std::list <WorkItem*> wl;
+ CRITICAL_SECTION cs;
+ HANDLE hEvent;
+public:
+ WorkList();
+ ~WorkList();
+ int initialize();
+ int cleanup();
+ void wait();
+ int add(WorkItem*);
+ int remove(WorkItem**);
+ bool isEmpty() {return wl.empty();}
+ };
+
+#endif // __WorkItem