aboutsummaryrefslogtreecommitdiff
path: root/src/windows/identity/kcreddb
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/identity/kcreddb')
-rw-r--r--src/windows/identity/kcreddb/Makefile52
-rw-r--r--src/windows/identity/kcreddb/attrib.c853
-rw-r--r--src/windows/identity/kcreddb/attrib.h55
-rw-r--r--src/windows/identity/kcreddb/buf.c391
-rw-r--r--src/windows/identity/kcreddb/buf.h78
-rw-r--r--src/windows/identity/kcreddb/credential.c1047
-rw-r--r--src/windows/identity/kcreddb/credential.h70
-rw-r--r--src/windows/identity/kcreddb/credset.c1132
-rw-r--r--src/windows/identity/kcreddb/credset.h75
-rw-r--r--src/windows/identity/kcreddb/credtype.c411
-rw-r--r--src/windows/identity/kcreddb/credtype.h55
-rw-r--r--src/windows/identity/kcreddb/identity.c1537
-rw-r--r--src/windows/identity/kcreddb/identity.h62
-rw-r--r--src/windows/identity/kcreddb/init.c91
-rw-r--r--src/windows/identity/kcreddb/kcdbconfig.csv15
-rw-r--r--src/windows/identity/kcreddb/kcreddb.h3212
-rw-r--r--src/windows/identity/kcreddb/kcreddbinternal.h60
-rw-r--r--src/windows/identity/kcreddb/kcreddbmain.c40
-rw-r--r--src/windows/identity/kcreddb/lang/en_us/kcredres.rc130
-rw-r--r--src/windows/identity/kcreddb/langres.h49
-rw-r--r--src/windows/identity/kcreddb/resource.h27
-rw-r--r--src/windows/identity/kcreddb/type.c1295
-rw-r--r--src/windows/identity/kcreddb/type.h216
23 files changed, 10953 insertions, 0 deletions
diff --git a/src/windows/identity/kcreddb/Makefile b/src/windows/identity/kcreddb/Makefile
new file mode 100644
index 0000000..24cc033
--- /dev/null
+++ b/src/windows/identity/kcreddb/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+MODULE=kcreddb
+!include <../config/Makefile.w32>
+
+INCFILES= \
+ $(INCDIR)\kcreddb.h
+
+OBJFILES= \
+ $(OBJ)\buf.obj \
+ $(OBJ)\attrib.obj \
+ $(OBJ)\credential.obj \
+ $(OBJ)\credset.obj \
+ $(OBJ)\credtype.obj \
+ $(OBJ)\identity.obj \
+ $(OBJ)\init.obj \
+ $(OBJ)\kcreddbmain.obj \
+ $(OBJ)\type.obj \
+ $(OBJ)\kcdbconfig.obj
+
+$(OBJ)\kcdbconfig.c: kcdbconfig.csv $(CONFDIR)\csvschema.cfg
+ $(CCSV) $** $@
+
+$(OBJ)\kcredres.res: lang\en_us\kcredres.rc
+ $(RC2RES)
+
+all: mkdirs $(INCFILES) $(OBJ)\kcredres.res $(OBJFILES)
+
+clean::
+ $(RM) $(INCFILES)
diff --git a/src/windows/identity/kcreddb/attrib.c b/src/windows/identity/kcreddb/attrib.c
new file mode 100644
index 0000000..e43540d
--- /dev/null
+++ b/src/windows/identity/kcreddb/attrib.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+#include<assert.h>
+
+CRITICAL_SECTION cs_attrib;
+hashtable * kcdb_attrib_namemap = NULL;
+kcdb_attrib_i ** kcdb_attrib_tbl = NULL;
+kcdb_attrib_i ** kcdb_property_tbl = NULL;
+kcdb_attrib_i * kcdb_attribs = NULL;
+
+void kcdb_attrib_add_ref_func(const void * key, void * va)
+{
+ kcdb_attrib_hold((kcdb_attrib_i *) va);
+}
+
+void kcdb_attrib_del_ref_func(const void * key, void * va)
+{
+ kcdb_attrib_release((kcdb_attrib_i *) va);
+}
+
+void kcdb_attrib_msg_completion(kmq_message * m)
+{
+ if(m && m->vparam) {
+ kcdb_attrib_release((kcdb_attrib_i *) m->vparam);
+ }
+}
+
+khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai)
+{
+ if(!ai)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_attrib);
+ ai->refcount++;
+ LeaveCriticalSection(&cs_attrib);
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai)
+{
+ if(!ai)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_attrib);
+ ai->refcount--;
+ LeaveCriticalSection(&cs_attrib);
+ return KHM_ERROR_SUCCESS;
+}
+
+void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai)
+{
+ kcdb_attrib_hold(ai);
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_ATTRIB, op, (void *) ai);
+}
+
+khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle vcred,
+ khm_int32 attr,
+ void * buf,
+ khm_size * pcb_buf)
+{
+ kcdb_cred * c;
+
+ c = (kcdb_cred *) vcred;
+
+ switch(attr) {
+ case KCDB_ATTR_NAME:
+ return kcdb_cred_get_name(vcred, buf, pcb_buf);
+
+ case KCDB_ATTR_ID:
+ if(buf && *pcb_buf >= sizeof(khm_ui_8)) {
+ *pcb_buf = sizeof(khm_int64);
+ *((khm_ui_8 *) buf) = (khm_ui_8) c->identity;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *pcb_buf = sizeof(khm_ui_8);
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ case KCDB_ATTR_ID_NAME:
+ return kcdb_identity_get_name((khm_handle) c->identity,
+ (wchar_t *) buf, pcb_buf);
+
+ case KCDB_ATTR_TYPE:
+ if(buf && *pcb_buf >= sizeof(khm_int32)) {
+ *pcb_buf = sizeof(khm_int32);
+ *((khm_int32 *) buf) = c->type;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *pcb_buf = sizeof(khm_int32);
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ case KCDB_ATTR_TYPE_NAME:
+ return kcdb_credtype_describe(c->type, buf,
+ pcb_buf, KCDB_TS_SHORT);
+
+ case KCDB_ATTR_TIMELEFT:
+ {
+ /* we are going to make liberal use of __int64 here. It
+ is equivalent to FILETIME and also the MSDN docs say we
+ should use it if the compiler supports it */
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ unsigned __int64 ftc;
+ SYSTEMTIME st;
+
+ if(!buf || *pcb_buf < sizeof(__int64)) {
+ *pcb_buf = sizeof(__int64);
+ rv = KHM_ERROR_TOO_LONG;
+ } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_EXPIRE)) {
+ *pcb_buf = sizeof(__int64);
+ /* setting the timeleft to _I64_MAX has the
+ interpretation that this credential does not
+ expire, which is the default behavior if the
+ expiration time is not known */
+ *((__int64 *) buf) = _I64_MAX;
+ } else {
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, (LPFILETIME) &ftc);
+ *((__int64 *) buf) =
+ *((__int64 *) kcdb_cred_buf_get(c,KCDB_ATTR_EXPIRE)) - ftc;
+ }
+
+ return rv;
+ }
+
+ case KCDB_ATTR_RENEW_TIMELEFT:
+ {
+ /* we are going to make liberal use of __int64 here. It
+ is equivalent to FILETIME and also the MSDN docs say we
+ should use it if the compiler supports it */
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ unsigned __int64 ftc;
+ SYSTEMTIME st;
+
+ if(!buf || *pcb_buf < sizeof(__int64)) {
+ *pcb_buf = sizeof(__int64);
+ rv = KHM_ERROR_TOO_LONG;
+ } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_RENEW_EXPIRE)) {
+ *pcb_buf = sizeof(__int64);
+ /* setting the timeleft to _I64_MAX has the
+ interpretation that this credential does not
+ expire, which is the default behavior if the
+ expiration time is not known */
+ *((__int64 *) buf) = _I64_MAX;
+ } else {
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, (LPFILETIME) &ftc);
+ *((__int64 *) buf) =
+ *((__int64 *) kcdb_cred_buf_get(c,KCDB_ATTR_RENEW_EXPIRE)) - ftc;
+ }
+
+ return rv;
+ }
+
+ case KCDB_ATTR_FLAGS:
+ if(buf && *pcb_buf >= sizeof(khm_int32)) {
+ *pcb_buf = sizeof(khm_int32);
+ *((khm_int32 *) buf) = c->flags;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *pcb_buf = sizeof(khm_int32);
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ default:
+ return KHM_ERROR_NOT_FOUND;
+ }
+}
+
+void kcdb_attrib_init(void)
+{
+ kcdb_attrib attrib;
+ wchar_t sbuf[256];
+
+ InitializeCriticalSection(&cs_attrib);
+ kcdb_attrib_namemap = hash_new_hashtable(
+ KCDB_ATTRIB_HASH_SIZE,
+ hash_string,
+ hash_string_comp,
+ kcdb_attrib_add_ref_func,
+ kcdb_attrib_del_ref_func);
+
+ kcdb_attrib_tbl =
+ malloc(sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1));
+ assert(kcdb_attrib_tbl != NULL);
+ ZeroMemory(kcdb_attrib_tbl,
+ sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1));
+
+ kcdb_property_tbl =
+ malloc(sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS);
+ assert(kcdb_property_tbl != NULL);
+ ZeroMemory(kcdb_property_tbl,
+ sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS);
+
+ kcdb_attribs = NULL;
+
+ /* register standard attributes */
+
+ /* Name */
+ attrib.id = KCDB_ATTR_NAME;
+ attrib.name = KCDB_ATTRNAME_NAME;
+ attrib.type = KCDB_TYPE_STRING;
+ LoadString(hinst_kcreddb, IDS_NAME, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags =
+ KCDB_ATTR_FLAG_REQUIRED |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(wchar_t);
+ attrib.compute_max_cbsize = KCDB_MAXCB_NAME;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* ID */
+ attrib.id = KCDB_ATTR_ID;
+ attrib.name = KCDB_ATTRNAME_ID;
+ attrib.type = KCDB_TYPE_INT64;
+ LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags =
+ KCDB_ATTR_FLAG_REQUIRED |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_SYSTEM |
+ KCDB_ATTR_FLAG_HIDDEN;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(khm_int32);
+ attrib.compute_max_cbsize = sizeof(khm_int32);
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* ID Name */
+ attrib.id = KCDB_ATTR_ID_NAME;
+ attrib.alt_id = KCDB_ATTR_ID;
+ attrib.name = KCDB_ATTRNAME_ID_NAME;
+ attrib.type = KCDB_TYPE_STRING;
+ LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags =
+ KCDB_ATTR_FLAG_REQUIRED |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_ALTVIEW |
+ KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(wchar_t);
+ attrib.compute_max_cbsize = KCDB_IDENT_MAXCB_NAME;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Type */
+ attrib.id = KCDB_ATTR_TYPE;
+ attrib.name = KCDB_ATTRNAME_TYPE;
+ attrib.type = KCDB_TYPE_INT32;
+ LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags =
+ KCDB_ATTR_FLAG_REQUIRED |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_SYSTEM |
+ KCDB_ATTR_FLAG_HIDDEN;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(khm_int32);
+ attrib.compute_max_cbsize = sizeof(khm_int32);
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Type Name */
+ attrib.id = KCDB_ATTR_TYPE_NAME;
+ attrib.alt_id = KCDB_ATTR_TYPE;
+ attrib.name = KCDB_ATTRNAME_TYPE_NAME;
+ attrib.type = KCDB_TYPE_STRING;
+ LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags =
+ KCDB_ATTR_FLAG_REQUIRED |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_ALTVIEW |
+ KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(wchar_t);
+ attrib.compute_max_cbsize = KCDB_MAXCB_NAME;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Parent Name */
+ attrib.id = KCDB_ATTR_PARENT_NAME;
+ attrib.name = KCDB_ATTRNAME_PARENT_NAME;
+ attrib.type = KCDB_TYPE_STRING;
+ LoadString(hinst_kcreddb, IDS_PARENT, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Issed On */
+ attrib.id = KCDB_ATTR_ISSUE;
+ attrib.name = KCDB_ATTRNAME_ISSUE;
+ attrib.type = KCDB_TYPE_DATE;
+ LoadString(hinst_kcreddb, IDS_ISSUED, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Expires On */
+ attrib.id = KCDB_ATTR_EXPIRE;
+ attrib.name = KCDB_ATTRNAME_EXPIRE;
+ attrib.type = KCDB_TYPE_DATE;
+ LoadString(hinst_kcreddb, IDS_EXPIRES, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Renewable Time Expires On */
+ attrib.id = KCDB_ATTR_RENEW_EXPIRE;
+ attrib.name = KCDB_ATTRNAME_RENEW_EXPIRE;
+ attrib.type = KCDB_TYPE_DATE;
+ LoadString(hinst_kcreddb, IDS_RENEW_EXPIRES,
+ sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Time Left */
+ attrib.id = KCDB_ATTR_TIMELEFT;
+ attrib.alt_id = KCDB_ATTR_EXPIRE;
+ attrib.name = KCDB_ATTRNAME_TIMELEFT;
+ attrib.type = KCDB_TYPE_INTERVAL;
+ LoadString(hinst_kcreddb, IDS_TIMELEFT, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_ALTVIEW |
+ KCDB_ATTR_FLAG_VOLATILE;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(__int64);
+ attrib.compute_max_cbsize = sizeof(__int64);
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Renewable Time Left */
+ attrib.id = KCDB_ATTR_RENEW_TIMELEFT;
+ attrib.alt_id = KCDB_ATTR_RENEW_EXPIRE;
+ attrib.name = KCDB_ATTRNAME_RENEW_TIMELEFT;
+ attrib.type = KCDB_TYPE_INTERVAL;
+ LoadString(hinst_kcreddb,
+ IDS_RENEW_TIMELEFT, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_ALTVIEW |
+ KCDB_ATTR_FLAG_VOLATILE;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(__int64);
+ attrib.compute_max_cbsize = sizeof(__int64);
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Location of Credential */
+ attrib.id = KCDB_ATTR_LOCATION;
+ attrib.name = KCDB_ATTRNAME_LOCATION;
+ attrib.type = KCDB_TYPE_STRING;
+ LoadString(hinst_kcreddb, IDS_LOCATION, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Lifetime */
+ attrib.id = KCDB_ATTR_LIFETIME;
+ attrib.name = KCDB_ATTRNAME_LIFETIME;
+ attrib.type = KCDB_TYPE_INTERVAL;
+ LoadString(hinst_kcreddb, IDS_LIFETIME, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Renewable Lifetime */
+ attrib.id = KCDB_ATTR_RENEW_LIFETIME;
+ attrib.name = KCDB_ATTRNAME_RENEW_LIFETIME;
+ attrib.type = KCDB_TYPE_INTERVAL;
+ LoadString(hinst_kcreddb,
+ IDS_RENEW_LIFETIME, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags = KCDB_ATTR_FLAG_SYSTEM;
+ attrib.compute_cb = NULL;
+ attrib.compute_min_cbsize = 0;
+ attrib.compute_max_cbsize = 0;
+
+ kcdb_attrib_register(&attrib, NULL);
+
+ /* Flags */
+ attrib.id = KCDB_ATTR_FLAGS;
+ attrib.name = KCDB_ATTRNAME_FLAGS;
+ attrib.type = KCDB_TYPE_INT32;
+ LoadString(hinst_kcreddb, IDS_FLAGS, sbuf, ARRAYLENGTH(sbuf));
+ attrib.short_desc = sbuf;
+ attrib.long_desc = NULL;
+ attrib.flags =
+ KCDB_ATTR_FLAG_REQUIRED |
+ KCDB_ATTR_FLAG_COMPUTED |
+ KCDB_ATTR_FLAG_SYSTEM |
+ KCDB_ATTR_FLAG_HIDDEN;
+ attrib.compute_cb = kcdb_attr_sys_cb;
+ attrib.compute_min_cbsize = sizeof(khm_int32);
+ attrib.compute_max_cbsize = sizeof(khm_int32);
+
+ kcdb_attrib_register(&attrib, NULL);
+}
+
+void kcdb_attrib_exit(void)
+{
+ DeleteCriticalSection(&cs_attrib);
+
+ if(kcdb_attrib_tbl)
+ free(kcdb_attrib_tbl);
+
+ if(kcdb_property_tbl)
+ free(kcdb_property_tbl);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_id(wchar_t *name, khm_int32 * id)
+{
+ kcdb_attrib_i * ai;
+
+ if(!name)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_attrib);
+ ai = hash_lookup(kcdb_attrib_namemap, (void *) name);
+ LeaveCriticalSection(&cs_attrib);
+
+ if(ai) {
+ *id = ai->attr.id;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *id = KCDB_ATTR_INVALID;
+ return KHM_ERROR_NOT_FOUND;
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_register(kcdb_attrib * attrib, khm_int32 * new_id)
+{
+ kcdb_attrib_i * ai;
+ size_t cb_name;
+ size_t cb_short_desc;
+ size_t cb_long_desc;
+ khm_int32 attr_id;
+ khm_boolean prop = FALSE;
+
+ if(!attrib ||
+ KHM_FAILED(kcdb_type_get_info(attrib->type, NULL)) ||
+ !attrib->name)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(FAILED(StringCbLength(attrib->name, KCDB_MAXCB_NAME, &cb_name)))
+ return KHM_ERROR_TOO_LONG;
+ cb_name += sizeof(wchar_t);
+
+ if(attrib->short_desc) {
+ if(FAILED(StringCbLength(attrib->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc)))
+ return KHM_ERROR_TOO_LONG;
+ cb_short_desc += sizeof(wchar_t);
+ } else
+ cb_short_desc = 0;
+
+ if(attrib->long_desc) {
+ if(FAILED(StringCbLength(attrib->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc)))
+ return KHM_ERROR_TOO_LONG;
+ cb_long_desc += sizeof(wchar_t);
+ } else
+ cb_long_desc = 0;
+
+ if((attrib->flags & KCDB_ATTR_FLAG_COMPUTED) &&
+ (!attrib->compute_cb ||
+ attrib->compute_min_cbsize <= 0 ||
+ attrib->compute_max_cbsize < attrib->compute_min_cbsize))
+ return KHM_ERROR_INVALID_PARM;
+
+ if ((attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) &&
+ KHM_FAILED(kcdb_attrib_get_info(attrib->alt_id,
+ NULL)))
+ return KHM_ERROR_INVALID_PARM;
+
+ prop = !!(attrib->flags & KCDB_ATTR_FLAG_PROPERTY);
+
+ EnterCriticalSection(&cs_attrib);
+
+ if(
+ !prop &&
+ (attrib->id < 0 || attrib->id > KCDB_ATTR_MAX_ID))
+ {
+ if(KHM_FAILED(kcdb_attrib_next_free_id(&attr_id))) {
+ LeaveCriticalSection(&cs_attrib);
+ return KHM_ERROR_NO_RESOURCES;
+ }
+ } else if (
+ prop &&
+ (attrib->id < KCDB_ATTR_MIN_PROP_ID || attrib->id > KCDB_ATTR_MAX_PROP_ID))
+ {
+ if(KHM_FAILED(kcdb_attrib_next_free_prop_id(&attr_id))) {
+ LeaveCriticalSection(&cs_attrib);
+ return KHM_ERROR_NO_RESOURCES;
+ }
+ } else {
+ attr_id = attrib->id;
+ }
+
+#ifdef DEBUG
+ assert(!prop || (attr_id >= KCDB_ATTR_MIN_PROP_ID && attr_id <= KCDB_ATTR_MAX_PROP_ID));
+ assert(prop || (attr_id >= 0 && attr_id <= KCDB_ATTR_MAX_ID));
+#endif
+
+ if((!prop && kcdb_attrib_tbl[attr_id]) ||
+ (prop && kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID]))
+ {
+ LeaveCriticalSection(&cs_attrib);
+ return KHM_ERROR_DUPLICATE;
+ }
+
+ ai = malloc(sizeof(kcdb_attrib_i));
+ ZeroMemory(ai, sizeof(kcdb_attrib_i));
+
+ ai->attr.type = attrib->type;
+ ai->attr.id = attr_id;
+ ai->attr.alt_id = attrib->alt_id;
+ ai->attr.flags = attrib->flags;
+ ai->attr.compute_cb = attrib->compute_cb;
+ ai->attr.compute_max_cbsize = attrib->compute_max_cbsize;
+ ai->attr.compute_min_cbsize = attrib->compute_min_cbsize;
+ ai->attr.name = malloc(cb_name);
+ StringCbCopy(ai->attr.name, cb_name, attrib->name);
+ if(cb_short_desc) {
+ ai->attr.short_desc = malloc(cb_short_desc);
+ StringCbCopy(ai->attr.short_desc, cb_short_desc, attrib->short_desc);
+ }
+ if(cb_long_desc) {
+ ai->attr.long_desc = malloc(cb_long_desc);
+ StringCbCopy(ai->attr.long_desc, cb_long_desc, attrib->long_desc);
+ }
+
+ LINIT(ai);
+
+ if(!prop)
+ kcdb_attrib_tbl[attr_id] = ai;
+ else
+ kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID] = ai;
+
+ LPUSH(&kcdb_attribs, ai);
+
+ hash_add(kcdb_attrib_namemap, (void *) ai->attr.name, ai);
+
+ LeaveCriticalSection(&cs_attrib);
+
+ kcdb_attrib_post_message(KCDB_OP_INSERT, ai);
+
+ if(new_id)
+ *new_id = attr_id;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_info(
+ khm_int32 id,
+ kcdb_attrib ** attrib)
+{
+ kcdb_attrib_i * ai;
+ khm_boolean prop;
+
+ if(id >= 0 && id <= KCDB_ATTR_MAX_ID)
+ prop = FALSE;
+ else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID)
+ prop = TRUE;
+ else
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_attrib);
+ if(prop)
+ ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID];
+ else
+ ai = kcdb_attrib_tbl[id];
+ LeaveCriticalSection(&cs_attrib);
+
+ if(ai) {
+ if(attrib) {
+ *attrib = &(ai->attr);
+ kcdb_attrib_hold(ai);
+ }
+ return KHM_ERROR_SUCCESS;
+ } else {
+ if(attrib)
+ *attrib = NULL;
+ return KHM_ERROR_NOT_FOUND;
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_release_info(kcdb_attrib * attrib)
+{
+ if(attrib)
+ kcdb_attrib_release((kcdb_attrib_i *) attrib);
+ return KHM_ERROR_SUCCESS;
+}
+
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_unregister(khm_int32 id)
+{
+ /*TODO: implement this */
+ return KHM_ERROR_NOT_IMPLEMENTED;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_describe(
+ khm_int32 id,
+ wchar_t * buffer,
+ khm_size * cbsize,
+ khm_int32 flags)
+{
+ kcdb_attrib_i * ai;
+ size_t cb_size = 0;
+ khm_boolean prop;
+
+ if(!cbsize)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(id >= 0 && id <= KCDB_ATTR_MAX_ID)
+ prop = FALSE;
+ else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID)
+ prop = TRUE;
+
+ if(prop)
+ ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID];
+ else
+ ai = kcdb_attrib_tbl[id];
+
+ if(!ai)
+ return KHM_ERROR_NOT_FOUND;
+
+ if((flags & KCDB_TS_SHORT) &&
+ ai->attr.short_desc)
+ {
+ if(FAILED(StringCbLength(ai->attr.short_desc, KCDB_MAXCB_SHORT_DESC, &cb_size)))
+ return KHM_ERROR_UNKNOWN;
+ cb_size += sizeof(wchar_t);
+
+ if(!buffer || *cbsize < cb_size) {
+ *cbsize = cb_size;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cbsize, ai->attr.short_desc);
+
+ *cbsize = cb_size;
+
+ return KHM_ERROR_SUCCESS;
+ } else {
+ if(FAILED(StringCbLength(ai->attr.long_desc, KCDB_MAXCB_LONG_DESC, &cb_size)))
+ return KHM_ERROR_UNKNOWN;
+ cb_size += sizeof(wchar_t);
+
+ if(!buffer || *cbsize < cb_size) {
+ *cbsize = cb_size;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cbsize, ai->attr.long_desc);
+
+ *cbsize = cb_size;
+
+ return KHM_ERROR_SUCCESS;
+ }
+}
+
+khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id)
+{
+ int i;
+
+ if(!id)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_attrib);
+ for(i=0;i < KCDB_ATTR_MAX_PROPS; i++) {
+ if(!kcdb_property_tbl[i])
+ break;
+ }
+ LeaveCriticalSection(&cs_attrib);
+
+ if(i < KCDB_ATTR_MAX_PROPS) {
+ *id = i + KCDB_ATTR_MIN_PROP_ID;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *id = KCDB_ATTR_INVALID;
+ return KHM_ERROR_NO_RESOURCES;
+ }
+}
+
+khm_int32 kcdb_attrib_next_free_id(khm_int32 * id)
+{
+ int i;
+
+ if(!id)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_attrib);
+ for(i=0;i<= KCDB_ATTR_MAX_ID; i++) {
+ if(!kcdb_attrib_tbl[i])
+ break;
+ }
+ LeaveCriticalSection(&cs_attrib);
+
+ if(i <= KCDB_ATTR_MAX_ID) {
+ *id = i;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *id = KCDB_ATTR_INVALID;
+ return KHM_ERROR_NO_RESOURCES;
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_count(
+ khm_int32 and_flags,
+ khm_int32 eq_flags,
+ khm_size * pcount)
+{
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ khm_size count = 0;
+ int i;
+
+ if(pcount == NULL)
+ return KHM_ERROR_INVALID_PARM;
+
+ eq_flags &= and_flags;
+
+ EnterCriticalSection(&cs_attrib);
+ for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) {
+ if(kcdb_attrib_tbl[i] &&
+ (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags)
+ count++;
+ }
+
+ for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) {
+ if(kcdb_property_tbl[i] &&
+ (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags)
+ count++;
+ }
+ LeaveCriticalSection(&cs_attrib);
+
+ *pcount = count;
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_attrib_get_ids(
+ khm_int32 and_flags,
+ khm_int32 eq_flags,
+ khm_int32 * plist,
+ khm_size * pcsize)
+{
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ khm_size count = 0;
+ int i;
+
+ if(plist == NULL || pcsize == NULL)
+ return KHM_ERROR_INVALID_PARM;
+
+ eq_flags &= and_flags;
+
+ EnterCriticalSection(&cs_attrib);
+ for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) {
+ if(kcdb_attrib_tbl[i] &&
+ (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) {
+ if(count >= *pcsize) {
+ rv = KHM_ERROR_TOO_LONG;
+ count++;
+ } else
+ plist[count++] = i;
+ }
+ }
+
+ for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) {
+ if(kcdb_property_tbl[i] &&
+ (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) {
+ if(count >= *pcsize) {
+ rv = KHM_ERROR_TOO_LONG;
+ count++;
+ } else
+ plist[count++] = i + KCDB_ATTR_MIN_PROP_ID;
+ }
+ }
+ LeaveCriticalSection(&cs_attrib);
+
+ *pcsize = count;
+
+ return rv;
+}
diff --git a/src/windows/identity/kcreddb/attrib.h b/src/windows/identity/kcreddb/attrib.h
new file mode 100644
index 0000000..5199aec
--- /dev/null
+++ b/src/windows/identity/kcreddb/attrib.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_ATTRIB_H
+#define __KHIMAIRA_KCDB_ATTRIB_H
+
+/* Attributes */
+
+typedef struct kcdb_attrib_i_t {
+ kcdb_attrib attr;
+
+ khm_int32 refcount;
+
+ struct kcdb_attrib_i_t * next;
+ struct kcdb_attrib_i_t * prev;
+} kcdb_attrib_i;
+
+#define KCDB_ATTRIB_HASH_SIZE 31
+
+void kcdb_attrib_init(void);
+void kcdb_attrib_exit(void);
+void kcdb_attrib_add_ref_func(const void * key, void * va);
+void kcdb_attrib_del_ref_func(const void * key, void * va);
+void kcdb_attrib_msg_completion(kmq_message * m);
+khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id);
+khm_int32 kcdb_attrib_next_free_id(khm_int32 * id);
+khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai);
+khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai);
+void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai);
+khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle cred, khm_int32 attr, void * buf, khm_size * pcb_buf);
+
+#endif \ No newline at end of file
diff --git a/src/windows/identity/kcreddb/buf.c b/src/windows/identity/kcreddb/buf.c
new file mode 100644
index 0000000..0f50be2
--- /dev/null
+++ b/src/windows/identity/kcreddb/buf.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+#include<assert.h>
+
+void kcdb_buf_new(kcdb_buf * buf, khm_size n_fields)
+{
+ buf->buffer = malloc(KCDB_BUF_CBBUF_INITIAL);
+ buf->cb_buffer = KCDB_BUF_CBBUF_INITIAL;
+ buf->cb_used = 0;
+
+ if(n_fields == KCDB_BUF_DEFAULT)
+ n_fields = KCDB_BUF_FIELDS_INITIAL;
+
+ assert(n_fields < KCDB_BUF_MAX_SLOTS);
+
+ buf->n_fields = n_fields;
+ buf->nc_fields = UBOUNDSS(n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH);
+ buf->fields = malloc(sizeof(buf->fields[0]) * buf->n_fields);
+ ZeroMemory(buf->fields, sizeof(buf->fields[0]) * buf->n_fields);
+}
+
+void kcdb_buf_delete(kcdb_buf * buf)
+{
+ buf->cb_buffer = 0;
+ buf->cb_used = 0;
+ if(buf->buffer)
+ free(buf->buffer);
+ buf->buffer = NULL;
+
+ buf->n_fields = 0;
+ buf->nc_fields = 0;
+ if(buf->fields)
+ free(buf->fields);
+ buf->fields = NULL;
+}
+
+static void kcdb_buf_assert_size(kcdb_buf * buf, khm_size cbsize)
+{
+ khm_size new_size;
+ void * new_buf;
+
+ /* should be less than or equal to the max signed 32 bit int */
+ assert(cbsize <= KHM_INT32_MAX);
+ if(cbsize <= buf->cb_buffer)
+ return;
+
+ new_size = UBOUNDSS(cbsize, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH);
+
+ assert(new_size > buf->cb_buffer && new_size > 0);
+
+ new_buf = malloc(new_size);
+ assert(new_buf != NULL);
+
+ memcpy(new_buf, buf->buffer, buf->cb_used);
+ free(buf->buffer);
+ buf->buffer = new_buf;
+}
+
+void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize)
+{
+ khm_size cbnew;
+ khm_ssize cbdelta;
+ khm_size cbold;
+ kcdb_buf_field * f;
+
+ cbnew = UBOUND32(cbsize);
+
+ assert(slot <= KCDB_BUF_APPEND);
+
+ if(slot == KCDB_BUF_APPEND) {
+ slot = kcdb_buf_slot_by_id(buf, id);
+ if(slot == KCDB_BUF_INVALID_SLOT)
+ slot = buf->n_fields;
+ }
+
+ assert(slot < KCDB_BUF_MAX_SLOTS);
+
+ if((slot + 1) > buf->nc_fields) {
+ kcdb_buf_field * nf;
+ khm_size ns;
+
+ ns = UBOUNDSS((slot + 1), KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH);
+
+ nf = malloc(sizeof(buf->fields[0]) * ns);
+ memcpy(nf, buf->fields, sizeof(buf->fields[0]) * buf->n_fields);
+
+ if(ns > buf->n_fields)
+ memset(&(nf[buf->n_fields]), 0, sizeof(buf->fields[0]) * (ns - buf->n_fields));
+
+ free(buf->fields);
+ buf->fields = nf;
+ buf->nc_fields = ns;
+ }
+
+ if((slot + 1) > buf->n_fields)
+ buf->n_fields = slot + 1;
+
+ f = &(buf->fields[slot]);
+
+ if(f->flags & KCDB_CREDF_FLAG_ALLOCD) {
+ /* there's already an allocation. we have to resize it to
+ accomodate the new size */
+ cbold = UBOUND32(f->cbsize);
+ /* demote before substraction */
+ cbdelta = ((khm_ssize) cbnew) - (khm_ssize) cbold;
+
+ if(cbnew > cbold) {
+ kcdb_buf_assert_size(buf, buf->cb_used + cbdelta);
+ }
+
+ if(buf->cb_used > f->offset + cbold) {
+ int i;
+
+ memmove(
+ ((BYTE *) buf->buffer) + (f->offset + cbnew),
+ ((BYTE *) buf->buffer) + (f->offset + cbold),
+ buf->cb_used - (f->offset + cbold));
+
+ for(i=0; i < (int) buf->n_fields; i++) {
+ if(i != slot &&
+ (buf->fields[i].flags & KCDB_CREDF_FLAG_ALLOCD) &&
+ buf->fields[i].offset > f->offset)
+ {
+ buf->fields[i].offset =
+ (khm_ui_4)(((khm_ssize) buf->fields[i].offset) + cbdelta);
+ }
+ }
+ }
+
+ /* demote integer before adding signed quantity */
+ buf->cb_used = (khm_size)(((khm_ssize) buf->cb_used) + cbdelta);
+
+ f->cbsize = (khm_ui_4) cbsize;
+
+ } else {
+ kcdb_buf_assert_size(buf, buf->cb_used + cbnew);
+ f->offset = (khm_ui_4) buf->cb_used;
+ f->cbsize = (khm_ui_4) cbsize;
+ buf->cb_used += cbnew;
+ }
+
+ if(cbsize == 0) {
+ f->flags &= ~KCDB_CREDF_FLAG_ALLOCD;
+ f->flags &= ~KCDB_CREDF_FLAG_DATA;
+ f->id = KCDB_BUFF_ID_INVALID;
+ } else {
+ f->flags |= KCDB_CREDF_FLAG_ALLOCD;
+ f->id = id;
+ }
+}
+
+void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src)
+{
+ khm_size cb_buf;
+ khm_size nc_fields;
+
+ cb_buf = UBOUNDSS(src->cb_used, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH);
+#if 0
+ /* replaced by UBOUNDSS() above */
+ (src->cb_used <= kcdb_cred_initial_size)? kcdb_cred_initial_size:
+ kcdb_cred_initial_size +
+ (((src->cb_used - (kcdb_cred_initial_size + 1)) / kcdb_cred_growth_factor + 1) * kcdb_cred_growth_factor);
+#endif
+
+ kcdb_buf_delete(dest);
+
+ dest->cb_buffer = cb_buf;
+ dest->cb_used = src->cb_used;
+ dest->buffer = malloc(cb_buf);
+ memcpy(dest->buffer, src->buffer, src->cb_used);
+
+ nc_fields = UBOUNDSS(src->n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH);
+ dest->nc_fields = nc_fields;
+ dest->n_fields = src->n_fields;
+ dest->fields = malloc(nc_fields * sizeof(dest->fields[0]));
+ memcpy(dest->fields, src->fields, src->n_fields * sizeof(dest->fields[0]));
+ if(dest->n_fields < dest->nc_fields)
+ memset(&(dest->fields[dest->n_fields]), 0, (src->nc_fields - src->n_fields) * sizeof(dest->fields[0]));
+}
+
+void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src)
+{
+ void * dest;
+ kcdb_buf_alloc(buf, slot, id, cb_src);
+ if(slot == KCDB_BUF_APPEND) {
+ slot = kcdb_buf_slot_by_id(buf, id);
+ if(slot == KCDB_BUF_INVALID_SLOT) {
+#ifdef DEBUG
+ assert(FALSE);
+#else
+ return;
+#endif
+ }
+ }
+ if(kcdb_buf_exist(buf, slot)) {
+ dest = kcdb_buf_get(buf, slot);
+ memcpy(dest, src, cb_src);
+
+ buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA;
+ }
+}
+
+int kcdb_buf_exist(kcdb_buf * buf, khm_size slot)
+{
+ if(slot >= buf->n_fields)
+ return 0;
+ return (buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD);
+}
+
+int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot)
+{
+ if(slot >= buf->n_fields)
+ return 0;
+ return (buf->fields[slot].flags & KCDB_CREDF_FLAG_DATA);
+}
+
+void * kcdb_buf_get(kcdb_buf * buf, khm_size slot)
+{
+ if(slot >= buf->n_fields ||
+ !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD))
+ return NULL;
+ return (((BYTE *) buf->buffer) + buf->fields[slot].offset);
+}
+
+khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot)
+{
+ if(slot >= buf->n_fields ||
+ !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD))
+ return 0;
+ return (buf->fields[slot].cbsize);
+}
+
+void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot)
+{
+ if(slot >= buf->n_fields ||
+ !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD))
+ return;
+
+ (buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA);
+}
+
+khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id)
+{
+ int i;
+
+ for(i=0; i < (int) buf->n_fields; i++) {
+ if(buf->fields[i].id == id)
+ break;
+ }
+
+ if(i < (int) buf->n_fields)
+ return i;
+ else
+ return KCDB_BUF_INVALID_SLOT;
+}
+
+/* API for accessing generic buffers */
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr(
+ khm_handle record,
+ khm_int32 attr_id,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcb_buf)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_get_attr(record, attr_id, attr_type, buffer, pcb_buf);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_get_attr(record, attr_id, attr_type, buffer, pcb_buf);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib(
+ khm_handle record,
+ wchar_t * attr_name,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcb_buf)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_get_attrib(record, attr_name, attr_type, buffer, pcb_buf);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_get_attrib(record, attr_name, attr_type, buffer, pcb_buf);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr_string(
+ khm_handle record,
+ khm_int32 attr_id,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_get_attr_string(record, attr_id, buffer, pcbbuf, flags);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_get_attr_string(record, attr_id, buffer, pcbbuf, flags);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib_string(
+ khm_handle record,
+ wchar_t * attr_name,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_get_attrib_string(record, attr_name, buffer, pcbbuf, flags);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_get_attrib_string(record, attr_name, buffer, pcbbuf, flags);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_set_attr(
+ khm_handle record,
+ khm_int32 attr_id,
+ void * buffer,
+ khm_size cbbuf)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_set_attr(record, attr_id, buffer, cbbuf);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_set_attr(record, attr_id, buffer, cbbuf);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_set_attrib(
+ khm_handle record,
+ wchar_t * attr_name,
+ void * buffer,
+ khm_size cbbuf)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_set_attrib(record, attr_name, buffer, cbbuf);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_set_attrib(record, attr_name, buffer, cbbuf);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_hold(khm_handle record)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_hold(record);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_hold(record);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_buf_release(khm_handle record)
+{
+ if(kcdb_cred_is_active_cred(record))
+ return kcdb_cred_release(record);
+ else if(kcdb_is_active_identity(record))
+ return kcdb_identity_release(record);
+ else
+ return KHM_ERROR_INVALID_PARM;
+}
+
diff --git a/src/windows/identity/kcreddb/buf.h b/src/windows/identity/kcreddb/buf.h
new file mode 100644
index 0000000..3ff1f04
--- /dev/null
+++ b/src/windows/identity/kcreddb/buf.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_BUF_H
+#define __KHIMAIRA_KCDB_BUF_H
+
+typedef struct tag_kcdb_buf_field {
+ khm_ui_2 id;
+ khm_ui_2 flags;
+ khm_ui_4 offset;
+ khm_ui_4 cbsize;
+} kcdb_buf_field;
+
+#define KCDB_CREDF_FLAG_EMPTY 0
+#define KCDB_CREDF_FLAG_DATA 1
+#define KCDB_CREDF_FLAG_INLINE 2
+#define KCDB_CREDF_FLAG_ALLOCD 4
+
+#define KCDB_BUFF_ID_INVALID 0xffff
+
+typedef struct tag_kcdb_buf {
+ void * buffer;
+ khm_size cb_buffer;
+ khm_size cb_used;
+
+ kcdb_buf_field * fields;
+ khm_size n_fields;
+ khm_size nc_fields;
+} kcdb_buf;
+
+#define KCDB_BUF_CBBUF_INITIAL 4096
+#define KCDB_BUF_CBBUF_GROWTH 4096
+#define KCDB_BUF_FIELDS_INITIAL 16
+#define KCDB_BUF_FIELDS_GROWTH 16
+
+#define KCDB_BUF_APPEND 0x8000
+
+#define KCDB_BUF_INVALID_SLOT 0xf0000000
+#define KCDB_BUF_DEFAULT 0xe0000000
+
+#define KCDB_BUF_MAX_SLOTS 0x00004000
+
+void kcdb_buf_new(kcdb_buf * buf, khm_size n_slots);
+void kcdb_buf_delete(kcdb_buf * buf);
+void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize);
+void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src);
+void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src);
+int kcdb_buf_exist(kcdb_buf * buf, khm_size slot);
+int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot);
+void * kcdb_buf_get(kcdb_buf * buf, khm_size slot);
+khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot);
+void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot);
+khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id);
+
+#endif
diff --git a/src/windows/identity/kcreddb/credential.c b/src/windows/identity/kcreddb/credential.c
new file mode 100644
index 0000000..1fe1dcd
--- /dev/null
+++ b/src/windows/identity/kcreddb/credential.c
@@ -0,0 +1,1047 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+#include<assert.h>
+
+/* cs_creds protects the *collection* of credentials, while l_creds
+ protects the *contents* of individual credentials. */
+CRITICAL_SECTION cs_creds;
+kcdb_cred * kcdb_creds = NULL;
+
+/* a read lock must be obtained when querying any existing credential.
+ a write lock must be obtained when modifying any existing credential.
+ */
+RWLOCK l_creds;
+
+/* serial number */
+khm_ui_8 kcdb_cred_id = 0;
+
+void kcdb_cred_init(void)
+{
+ InitializeCriticalSection(&cs_creds);
+ InitializeRwLock(&l_creds);
+ kcdb_cred_id = 0;
+}
+
+void kcdb_cred_exit(void)
+{
+ /*TODO: Free the credentials */
+ DeleteCriticalSection(&cs_creds);
+ DeleteRwLock(&l_creds);
+}
+
+/*! \internal
+
+ can be called by kcdb_cred_dup with a write lock on l_creds and in other
+ places with a read lock on l_creds. New credentials must be creatable while
+ holding either lock. */
+KHMEXP khm_int32 KHMAPI kcdb_cred_create(
+ wchar_t * name,
+ khm_handle identity,
+ khm_int32 cred_type,
+ khm_handle * result)
+{
+ kcdb_cred * cred;
+ size_t cb_name;
+
+ if(!name || !result ||
+ FAILED(StringCbLength(name, KCDB_CRED_MAXCB_NAME, &cb_name)) ||
+ KHM_FAILED(kcdb_credtype_get_info(cred_type, NULL)) ||
+ KHM_FAILED(kcdb_identity_hold(identity))
+ )
+ {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ cb_name += sizeof(wchar_t);
+
+ cred = malloc(sizeof(kcdb_cred));
+ ZeroMemory(cred, sizeof(kcdb_cred));
+
+ cred->magic = KCDB_CRED_MAGIC;
+ cred->identity = identity;
+ cred->name = malloc(cb_name);
+ StringCbCopy(cred->name, cb_name, name);
+ cred->type = cred_type;
+
+ cred->refcount = 1; /* initially held */
+
+ LINIT(cred);
+
+ kcdb_buf_new(&cred->buf, KCDB_ATTR_MAX_ID + 1);
+
+ /* Not obtaining a write lock on l_cred on purpose.
+ Well, because no one should be referencing this credential until
+ this function returns. */
+ EnterCriticalSection(&cs_creds);
+ cred->id = kcdb_cred_id++;
+ LPUSH(&kcdb_creds, cred);
+ LeaveCriticalSection(&cs_creds);
+
+ *result = cred;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_update(
+ khm_handle vdest,
+ khm_handle vsrc)
+{
+ khm_int32 rv = KHM_ERROR_EQUIVALENT;
+ kcdb_cred * src;
+ kcdb_cred * dest;
+ kcdb_type * t;
+ kcdb_attrib * a;
+ void * srcbuf;
+ void * destbuf;
+ khm_size cbsrcbuf;
+ khm_size cbdestbuf;
+
+ int i;
+
+ kcdb_cred_lock_write();
+
+ if(!kcdb_cred_is_active_cred(vsrc) ||
+ !kcdb_cred_is_active_cred(vdest))
+ goto _exit;
+
+ src = (kcdb_cred *) vsrc;
+ dest = (kcdb_cred *) vdest;
+
+ for(i=0;i<KCDB_ATTR_MAX_ID;i++) {
+ if(kcdb_cred_val_exist(src, i)) {
+ /*NOTE: the logic here has to reflect the logic in
+ kcdb_cred_set_attr() */
+ if(KHM_FAILED(kcdb_attrib_get_info(i, &a)))
+ continue;
+
+ if((a->flags & KCDB_ATTR_FLAG_COMPUTED) ||
+ KHM_FAILED(kcdb_type_get_info(a->type, &t))) {
+ kcdb_attrib_release_info(a);
+ continue;
+ }
+
+ srcbuf = kcdb_cred_buf_get(src,i);
+ cbsrcbuf = kcdb_cred_buf_size(src, i);
+
+ if(kcdb_cred_val_exist(dest, i)) {
+ destbuf = kcdb_cred_buf_get(dest, i);
+ cbdestbuf = kcdb_cred_buf_size(dest, i);
+
+ if(!t->comp(srcbuf, cbsrcbuf, destbuf, cbdestbuf))
+ goto _skip_copy;
+ }
+
+ kcdb_buf_set_value(&dest->buf, i, i, srcbuf, cbsrcbuf);
+ rv = KHM_ERROR_SUCCESS;
+
+_skip_copy:
+ kcdb_attrib_release_info(a);
+ kcdb_type_release_info(t);
+ }
+ }
+
+ if (dest->flags != src->flags) {
+ khm_int32 old_flags;
+
+ old_flags = dest->flags;
+
+ dest->flags = (src->flags & ~KCDB_CRED_FLAGMASK_ADDITIVE) |
+ ((src->flags | dest->flags) & KCDB_CRED_FLAGMASK_ADDITIVE);
+
+ if (dest->flags != old_flags)
+ rv = KHM_ERROR_SUCCESS;
+ }
+
+_exit:
+ kcdb_cred_unlock_write();
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_dup(
+ khm_handle vcred,
+ khm_handle * pnewcred)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+ kcdb_cred * newcred;
+ khm_handle vnewcred;
+
+ if(!pnewcred)
+ return KHM_ERROR_INVALID_PARM;
+
+ *pnewcred = NULL;
+
+ kcdb_cred_lock_write();
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ if(KHM_FAILED(kcdb_cred_create(
+ cred->name,
+ cred->identity,
+ cred->type,
+ &vnewcred)))
+ {
+ code = KHM_ERROR_UNKNOWN;
+ goto _exit;
+ }
+
+ newcred = (kcdb_cred *) vnewcred;
+
+ newcred->flags = cred->flags;
+
+ kcdb_buf_dup(&newcred->buf, &cred->buf);
+
+ /* newcred is already held from the call to kcdb_cred_create */
+ *pnewcred = (khm_handle) newcred;
+
+_exit:
+ kcdb_cred_unlock_write();
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_serial(
+ khm_handle vcred,
+ khm_ui_8 * pserial)
+{
+ kcdb_cred * c;
+
+ if(!pserial)
+ return KHM_ERROR_INVALID_PARM;
+
+ LockObtainRead(&l_creds);
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ LockReleaseRead(&l_creds);
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ c = (kcdb_cred *) vcred;
+
+ *pserial = c->id;
+
+ LockReleaseRead(&l_creds);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_identity(
+ khm_handle vcred,
+ khm_handle id)
+{
+ kcdb_cred * c;
+
+ if(!kcdb_is_identity(id))
+ return KHM_ERROR_INVALID_PARM;
+
+ kcdb_cred_lock_write();
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ kcdb_cred_unlock_write();
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ c = (kcdb_cred *) vcred;
+
+ if(c->identity) {
+ kcdb_identity_release((khm_handle) c->identity);
+ }
+ kcdb_identity_hold(id);
+ c->identity = (kcdb_identity *) id;
+
+ kcdb_cred_unlock_write();
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_type(
+ khm_handle vcred,
+ khm_int32 * type)
+{
+ kcdb_cred * c;
+
+ if(!type)
+ return KHM_ERROR_INVALID_PARM;
+
+ LockObtainRead(&l_creds);
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ LockReleaseRead(&l_creds);
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ c = (kcdb_cred *) vcred;
+
+ *type = c->type;
+
+ LockReleaseRead(&l_creds);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_attrib(
+ khm_handle cred,
+ wchar_t * name,
+ void * buffer,
+ khm_size cbbuf)
+{
+ khm_int32 attr_id = -1;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))
+ return KHM_ERROR_INVALID_PARM;
+
+ return kcdb_cred_set_attr(
+ cred,
+ attr_id,
+ buffer,
+ cbbuf);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_attr(
+ khm_handle vcred,
+ khm_int32 attr_id,
+ void * buffer,
+ khm_size cbbuf)
+{
+ kcdb_cred * cred;
+ kcdb_type * type = NULL;
+ kcdb_attrib * attrib = NULL;
+ khm_size cbdest;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ kcdb_cred_lock_write();
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ kcdb_cred_unlock_write();
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {
+ kcdb_cred_unlock_write();
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)
+ {
+ kcdb_cred_unlock_write();
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_INVALID_OPERATION;
+ }
+
+ if (buffer == 0) {
+ /* we are removing the value */
+ kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0);
+ code = KHM_ERROR_SUCCESS;
+ goto _exit;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {
+ kcdb_cred_unlock_write();
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(!(type->isValid(buffer,cbbuf))) {
+ code = KHM_ERROR_TYPE_MISMATCH;
+ goto _exit;
+ }
+
+ if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ kcdb_buf_alloc(&cred->buf, attr_id, attr_id, cbdest);
+ if(!kcdb_cred_buf_exist(cred, attr_id)) {
+ code = KHM_ERROR_NO_RESOURCES;
+ goto _exit;
+ }
+
+ if(KHM_FAILED(code =
+ type->dup(buffer, cbbuf, kcdb_cred_buf_get(cred,attr_id), &cbdest)))
+ {
+ kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0);
+ goto _exit;
+ }
+
+ kcdb_buf_set_value_flag(&cred->buf, attr_id);
+
+_exit:
+ kcdb_cred_unlock_write();
+
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+ if(type)
+ kcdb_type_release_info(type);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib(
+ khm_handle cred,
+ wchar_t * name,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * cbbuf)
+{
+ khm_int32 attr_id = -1;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))
+ return KHM_ERROR_NOT_FOUND;
+
+ return kcdb_cred_get_attr(
+ cred,
+ attr_id,
+ attr_type,
+ buffer,
+ cbbuf);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib_string(
+ khm_handle cred,
+ wchar_t * name,
+ wchar_t * buffer,
+ khm_size * cbbuf,
+ khm_int32 flags)
+{
+ khm_int32 attr_id = -1;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))
+ return KHM_ERROR_NOT_FOUND;
+
+ return kcdb_cred_get_attr_string(
+ cred,
+ attr_id,
+ buffer,
+ cbbuf,
+ flags);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr(
+ khm_handle vcred,
+ khm_int32 attr_id,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcbbuf)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred = NULL;
+ kcdb_attrib * attrib = NULL;
+ kcdb_type * type = NULL;
+
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_UNKNOWN;
+ }
+
+ if(attr_type)
+ *attr_type = attrib->type;
+
+ LockObtainRead(&l_creds);
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ if(!buffer && !pcbbuf) {
+ /* in this case the caller is only trying to determine if the
+ field contains data. We assume that computed fields are
+ always non-null. */
+ code = (kcdb_cred_val_exist(cred, attr_id) ||
+ (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;
+ goto _exit;
+ }
+
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {
+ code = attrib->compute_cb(
+ vcred,
+ attr_id,
+ buffer,
+ pcbbuf);
+ } else if (kcdb_cred_val_exist(cred, attr_id)) {
+ code = type->dup(
+ kcdb_cred_buf_get(cred, attr_id),
+ kcdb_cred_buf_size(cred, attr_id),
+ buffer,
+ pcbbuf);
+ } else {
+ code = KHM_ERROR_NOT_FOUND;
+ }
+
+_exit:
+ LockReleaseRead(&l_creds);
+ if(type)
+ kcdb_type_release_info(type);
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr_string(
+ khm_handle vcred,
+ khm_int32 attr_id,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred = NULL;
+ kcdb_attrib * attrib = NULL;
+ kcdb_type * type = NULL;
+
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {
+ code = KHM_ERROR_UNKNOWN;
+ goto _exit;
+ }
+
+ LockObtainRead(&l_creds);
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ if(!buffer && !pcbbuf) {
+ /* in this case the caller is only trying to determine if the field
+ contains data. We assume that computed fields are always non-null. */
+ code = (kcdb_cred_val_exist(cred, attr_id) ||
+ (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;
+ goto _exit;
+ }
+
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {
+ void * buf;
+ khm_size cbbuf;
+
+ code = attrib->compute_cb(
+ vcred,
+ attr_id,
+ NULL,
+ &cbbuf);
+ if(code == KHM_ERROR_TOO_LONG) {
+ buf = malloc(cbbuf);
+ code = attrib->compute_cb(
+ vcred,
+ attr_id,
+ buf,
+ &cbbuf);
+ if(KHM_SUCCEEDED(code)) {
+ code = type->toString(
+ buf,
+ cbbuf,
+ buffer,
+ pcbbuf,
+ flags);
+ }
+ free(buf);
+ }
+ } else {
+ if(kcdb_cred_buf_exist(cred, attr_id)) {
+ code = type->toString(
+ kcdb_cred_buf_get(cred, attr_id),
+ kcdb_cred_buf_size(cred, attr_id),
+ buffer,
+ pcbbuf,
+ flags);
+ } else
+ code = KHM_ERROR_NOT_FOUND;
+ }
+
+_exit:
+ LockReleaseRead(&l_creds);
+ if(type)
+ kcdb_type_release_info(type);
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+
+ return code;
+}
+
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_name(
+ khm_handle vcred,
+ wchar_t * buffer,
+ khm_size * cbbuf)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred = NULL;
+ size_t cbsize;
+
+ if(!cbbuf)
+ return KHM_ERROR_INVALID_PARM;
+
+ LockObtainRead(&l_creds);
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ if(FAILED(StringCbLength(cred->name, KCDB_CRED_MAXCB_NAME, &cbsize))) {
+ code = KHM_ERROR_UNKNOWN;
+ goto _exit;
+ }
+
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cbbuf < cbsize) {
+ *cbbuf = cbsize;
+ code = KHM_ERROR_TOO_LONG;
+ goto _exit;
+ }
+
+ StringCbCopy(buffer, *cbbuf, cred->name);
+
+ *cbbuf = cbsize;
+
+_exit:
+
+ LockReleaseRead(&l_creds);
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_identity(
+ khm_handle vcred,
+ khm_handle * identity)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+
+ if(!identity)
+ return KHM_ERROR_INVALID_PARM;
+
+ LockObtainRead(&l_creds);
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ kcdb_identity_hold((khm_handle) cred->identity);
+
+ *identity = cred->identity;
+
+_exit:
+ LockReleaseRead(&l_creds);
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_hold(khm_handle vcred)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+
+ kcdb_cred_lock_write();
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ cred->refcount++;
+
+_exit:
+ kcdb_cred_unlock_write();
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_release(khm_handle vcred)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+
+ kcdb_cred_lock_write();
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ cred->refcount--;
+
+_exit:
+ kcdb_cred_unlock_write();
+
+ kcdb_cred_check_and_delete(vcred);
+
+ return code;
+}
+
+void kcdb_cred_check_and_delete(khm_handle vcred)
+{
+ kcdb_cred * cred;
+
+ LockObtainRead(&l_creds);
+ if(!kcdb_cred_is_cred(vcred)) {
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ if(!(cred->flags & KCDB_CRED_FLAG_DELETED))
+ goto _exit;
+
+ if(cred->refcount)
+ goto _exit;
+
+ LockReleaseRead(&l_creds);
+ kcdb_cred_lock_write();
+ if(!kcdb_cred_is_cred(vcred)) {
+ /* did we lose the race? */
+ goto _exit2;
+ }
+
+ cred->magic = 0; /* no longer a cred */
+ kcdb_identity_release(cred->identity);
+
+ EnterCriticalSection(&cs_creds);
+ LDELETE(&kcdb_creds, cred);
+ LeaveCriticalSection(&cs_creds);
+
+ kcdb_buf_delete(&cred->buf);
+ free(cred->name);
+ free(cred);
+
+ /*TODO: notifications */
+
+_exit2:
+ kcdb_cred_unlock_write();
+ return;
+
+_exit:
+ LockReleaseRead(&l_creds);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_delete(khm_handle vcred)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+
+ kcdb_cred_lock_write();
+
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = (kcdb_cred *) vcred;
+
+ cred->flags |= KCDB_CRED_FLAG_DELETED;
+
+_exit:
+ kcdb_cred_unlock_write();
+
+ kcdb_cred_check_and_delete(vcred);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_creds_comp_attrib(
+ khm_handle cred1,
+ khm_handle cred2,
+ wchar_t * name)
+{
+ khm_int32 attr_id;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id)))
+ return 0;
+
+ return kcdb_creds_comp_attr(cred1, cred2, attr_id);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_creds_comp_attr(
+ khm_handle vcred1,
+ khm_handle vcred2,
+ khm_int32 attr_id)
+{
+ khm_int32 code = 0;
+ kcdb_cred * cred1;
+ kcdb_cred * cred2;
+ kcdb_attrib * attrib = NULL;
+ kcdb_type * type = NULL;
+
+ if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID)
+ return 0;
+
+ cred1 = (kcdb_cred *) vcred1;
+ cred2 = (kcdb_cred *) vcred2;
+
+ LockObtainRead(&l_creds);
+ if(
+ !kcdb_cred_is_active_cred(vcred1) ||
+ !kcdb_cred_is_active_cred(vcred2))
+ goto _exit;
+
+ cred1 = (kcdb_cred *) vcred1;
+ cred2 = (kcdb_cred *) vcred2;
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib)))
+ goto _exit;
+
+ if(!(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)) {
+ int nc = 0;
+
+ if(!kcdb_cred_val_exist(cred1, attr_id)) {
+ code = -1;
+ nc = 1;
+ }
+ if(!kcdb_cred_val_exist(cred2, attr_id)) {
+ code += 1;
+ nc = 1;
+ }
+
+ if(nc)
+ goto _exit;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type)))
+ goto _exit;
+
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {
+ void * buf1 = NULL;
+ void * buf2 = NULL;
+ khm_size cb1;
+ khm_size cb2;
+
+ code = 0;
+
+ if(attrib->compute_cb(vcred1, attr_id, NULL, &cb1) != KHM_ERROR_TOO_LONG)
+ goto _exit_1;
+
+ if(attrib->compute_cb(vcred2, attr_id, NULL, &cb2) != KHM_ERROR_TOO_LONG)
+ goto _exit_1;
+
+ if(cb1) {
+ buf1 = malloc(cb1);
+ if(KHM_FAILED(attrib->compute_cb(vcred1, attr_id, buf1, &cb1)))
+ goto _exit_1;
+ }
+ if(cb2) {
+ buf2 = malloc(cb2);
+ if(KHM_FAILED(attrib->compute_cb(vcred2, attr_id, buf2, &cb2)))
+ goto _exit_1;
+ }
+ code = type->comp(
+ buf1, cb1,
+ buf2, cb2);
+_exit_1:
+ if(buf1)
+ free(buf1);
+ if(buf2)
+ free(buf2);
+
+ } else {
+ code = type->comp(
+ kcdb_cred_buf_get(cred1, attr_id),
+ kcdb_cred_buf_size(cred1, attr_id),
+ kcdb_cred_buf_get(cred2, attr_id),
+ kcdb_cred_buf_size(cred2, attr_id));
+ }
+
+_exit:
+ LockReleaseRead(&l_creds);
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+ if(type)
+ kcdb_type_release_info(type);
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_creds_is_equal(
+ khm_handle vcred1,
+ khm_handle vcred2)
+{
+ khm_int32 code = 0;
+ kcdb_cred * cred1;
+ kcdb_cred * cred2;
+
+ LockObtainRead(&l_creds);
+ if(!kcdb_cred_is_active_cred(vcred1) ||
+ !kcdb_cred_is_active_cred(vcred2))
+ goto _exit;
+
+ if(vcred1 == vcred2) {
+ code = TRUE;
+ goto _exit;
+ }
+
+ cred1 = vcred1;
+ cred2 = vcred2;
+
+ if(cred1->identity == cred2->identity &&
+ cred1->type == cred2->type &&
+ !wcscmp(cred1->name, cred2->name)) {
+ code = TRUE;
+ }
+
+_exit:
+ LockReleaseRead(&l_creds);
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_get_flags(
+ khm_handle vcred,
+ khm_int32 * pflags)
+{
+ khm_int32 f;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+ int release_lock = TRUE;
+
+ if (pflags == NULL)
+ return KHM_ERROR_INVALID_PARM;
+
+ LockObtainRead(&l_creds);
+ if (!kcdb_cred_is_active_cred(vcred)) {
+ *pflags = 0;
+ rv = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = vcred;
+ f = cred->flags;
+
+ /* Update flags if necessary */
+
+ if (!(f & KCDB_CRED_FLAG_EXPIRED) &&
+ kcdb_cred_buf_exist(cred, KCDB_ATTR_EXPIRE)) {
+
+ khm_int64 ftc;
+
+ GetSystemTimeAsFileTime((LPFILETIME) &ftc);
+ if (ftc > *((khm_int64 *)
+ kcdb_cred_buf_get(cred, KCDB_ATTR_EXPIRE)))
+ f |= KCDB_CRED_FLAG_EXPIRED;
+ }
+
+#if 0
+ /* Commented out: if the credential has expired, then checking the
+ renewable time is not useful */
+ if (!(f & KCDB_CRED_FLAG_INVALID)) {
+ if (f & KCDB_CRED_FLAG_RENEWABLE) {
+ if (kcdb_cred_buf_exist(cred, KCDB_ATTR_RENEW_EXPIRE)) {
+ khm_int64 ftc;
+
+ GetSystemTimeAsFileTime((LPFILETIME) &ftc);
+ if (ftc > *((khm_int64 *) kcdb_cred_buf_get(cred, KCDB_ATTR_RENEW_EXPIRE)))
+ f |= KCDB_CRED_FLAG_INVALID;
+ }
+ } else {
+ if (f & KCDB_CRED_FLAG_EXPIRED)
+ f |= KCDB_CRED_FLAG_INVALID;
+ }
+ }
+
+ /* Commented out: this is a read operation. We shouldn't attempt
+ to lock for writing */
+ if (f != cred->flags) {
+ LockReleaseRead(&l_creds);
+ LockObtainWrite(&l_creds);
+ /* Did we lose a race? */
+ if (kcdb_cred_is_active_cred(vcred))
+ cred->flags = f;
+ else {
+ rv = KHM_ERROR_INVALID_PARM;
+ f = 0;
+ }
+ LockReleaseWrite(&l_creds);
+ release_lock = FALSE;
+ }
+#endif
+
+ *pflags = f;
+
+ _exit:
+ if (release_lock)
+ LockReleaseRead(&l_creds);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_set_flags(
+ khm_handle vcred,
+ khm_int32 flags,
+ khm_int32 mask)
+{
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ kcdb_cred * cred;
+
+ LockObtainWrite(&l_creds);
+ if(!kcdb_cred_is_active_cred(vcred)) {
+ rv = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ cred = vcred;
+
+ flags &= ~(KCDB_CRED_FLAG_DELETED);
+ mask &= ~(KCDB_CRED_FLAG_DELETED);
+
+ cred->flags =
+ (cred->flags & (~mask)) |
+ (flags & mask);
+
+ _exit:
+ LockReleaseWrite(&l_creds);
+ return rv;
+}
diff --git a/src/windows/identity/kcreddb/credential.h b/src/windows/identity/kcreddb/credential.h
new file mode 100644
index 0000000..8104f68
--- /dev/null
+++ b/src/windows/identity/kcreddb/credential.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_CREDENTIAL_H
+#define __KHIMAIRA_KCDB_CREDENTIAL_H
+
+/* Credentials */
+
+typedef struct kcdb_cred_t {
+ khm_int32 magic;
+ khm_ui_8 id; /* serial number */
+ kcdb_identity * identity;
+ khm_int32 type;
+ wchar_t * name;
+
+ khm_int32 flags;
+ khm_int32 refcount;
+
+ kcdb_buf buf;
+
+ LDCL(struct kcdb_cred_t);
+} kcdb_cred;
+
+#define KCDB_CRED_MAGIC 0x38fb84a6
+
+extern CRITICAL_SECTION cs_creds;
+extern kcdb_cred * kcdb_creds;
+extern RWLOCK l_creds;
+extern khm_ui_8 kcdb_cred_id;
+
+#define kcdb_cred_val_exist(c,a) kcdb_buf_val_exist(&(c)->buf, a)
+#define kcdb_cred_buf_exist(c,a) kcdb_buf_exist(&(c)->buf, a)
+#define kcdb_cred_buf_get(c,a) kcdb_buf_get(&(c)->buf, a)
+#define kcdb_cred_buf_size(c,a) kcdb_buf_size(&(c)->buf, a)
+
+#define kcdb_cred_is_cred(c) ((c) && ((kcdb_cred *) c)->magic == KCDB_CRED_MAGIC)
+#define kcdb_cred_is_active_cred(c) (kcdb_cred_is_cred(c) && !(((kcdb_cred *) c)->flags & KCDB_CRED_FLAG_DELETED))
+#define kcdb_cred_lock_read() (LockObtainRead(&l_creds))
+#define kcdb_cred_unlock_read() (LockReleaseRead(&l_creds))
+#define kcdb_cred_lock_write() (LockObtainWrite(&l_creds))
+#define kcdb_cred_unlock_write() (LockReleaseWrite(&l_creds))
+
+void kcdb_cred_init(void);
+void kcdb_cred_exit(void);
+void kcdb_cred_check_and_delete(khm_handle vcred);
+
+#endif
diff --git a/src/windows/identity/kcreddb/credset.c b/src/windows/identity/kcreddb/credset.c
new file mode 100644
index 0000000..3a39d48
--- /dev/null
+++ b/src/windows/identity/kcreddb/credset.c
@@ -0,0 +1,1132 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+#include<assert.h>
+
+CRITICAL_SECTION cs_credset;
+kcdb_credset * kcdb_credsets = NULL;
+kcdb_credset * kcdb_root_credset = NULL;
+
+void kcdb_credset_init(void)
+{
+ khm_handle rc;
+
+ InitializeCriticalSection(&cs_credset);
+ kcdb_credsets = NULL;
+
+ kcdb_credset_create(&rc);
+ kcdb_root_credset = (kcdb_credset *) rc;
+ kcdb_root_credset->flags |= KCDB_CREDSET_FLAG_ROOT;
+}
+
+void kcdb_credset_exit(void)
+{
+ /*TODO: free the credsets */
+ DeleteCriticalSection(&cs_credset);
+}
+
+/* called on an unreleased credset, or with credset::cs held */
+void kcdb_credset_buf_new(kcdb_credset * cs)
+{
+ cs->clist = malloc(KCDB_CREDSET_INITIAL_SIZE * sizeof(kcdb_credset_credref));
+ ZeroMemory(cs->clist, KCDB_CREDSET_INITIAL_SIZE * sizeof(kcdb_credset_credref));
+ cs->nc_clist = KCDB_CREDSET_INITIAL_SIZE;
+ cs->nclist = 0;
+}
+
+/* called on an unreleased credset, or with credset::cs held */
+void kcdb_credset_buf_delete(kcdb_credset * cs)
+{
+ free(cs->clist);
+ cs->nc_clist = 0;
+ cs->nclist = 0;
+}
+
+void kcdb_credset_buf_assert_size(kcdb_credset * cs, khm_int32 nclist)
+{
+ if(cs->nc_clist < nclist) {
+ kcdb_credset_credref * new_clist;
+
+ /* nclist had better be greater than KCDB_CREDSET_INITIAL_SIZE */
+ nclist = KCDB_CREDSET_INITIAL_SIZE +
+ (((nclist - (KCDB_CREDSET_INITIAL_SIZE + 1)) / KCDB_CREDSET_GROWTH_FACTOR) + 1) *
+ KCDB_CREDSET_GROWTH_FACTOR;
+
+ new_clist = calloc(nclist, sizeof(kcdb_credset_credref));
+
+ memcpy(new_clist, cs->clist, cs->nclist * sizeof(kcdb_credset_credref));
+
+ free(cs->clist);
+
+ cs->clist = new_clist;
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result)
+{
+ kcdb_credset * cs;
+
+ cs = malloc(sizeof(kcdb_credset));
+ ZeroMemory(cs, sizeof(kcdb_credset));
+
+ cs->magic = KCDB_CREDSET_MAGIC;
+ InitializeCriticalSection(&(cs->cs));
+ LINIT(cs);
+ kcdb_credset_buf_new(cs);
+ cs->version = 0;
+ cs->seal_count = 0;
+
+ EnterCriticalSection(&cs_credset);
+ LPUSH(&kcdb_credsets, cs);
+ LeaveCriticalSection(&cs_credset);
+
+ *result = (khm_handle) cs;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_delete(khm_handle vcredset)
+{
+ kcdb_credset * cs;
+ int i;
+
+ if(!kcdb_credset_is_credset(vcredset)) {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ cs = (kcdb_credset *) vcredset;
+
+ EnterCriticalSection(&cs_credset);
+ LDELETE(&kcdb_credsets, cs);
+ LeaveCriticalSection(&cs_credset);
+
+ EnterCriticalSection(&(cs->cs));
+ cs->magic = 0;
+
+ for(i=0;i<cs->nclist;i++) {
+ if(cs->clist[i].cred) {
+ kcdb_cred_release((khm_handle) cs->clist[i].cred);
+ }
+ }
+ kcdb_credset_buf_delete(cs);
+
+ LeaveCriticalSection(&(cs->cs));
+ DeleteCriticalSection(&(cs->cs));
+
+ free(cs);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+/*! \internal
+
+Collect credentials from cs2 to cs1 which have already been selected into
+cl1 and cl2.
+
+- Credentials in cl2 that are not in cl1 will get added to cs1
+- Credentials in cl1 that are not in cl2 will get removed from cs1
+- Credentials in cl1 and cl2 will be updated in cs1
+
+cl1 and cl2 will be modified.
+*/
+khm_int32 kcdb_credset_collect_core(
+ kcdb_credset * cs1,
+ kcdb_cred ** cl1,
+ khm_int32 ncl1,
+ kcdb_credset * cs2,
+ kcdb_cred ** cl2,
+ khm_int32 ncl2,
+ khm_int32 * delta)
+{
+ int i, j;
+ int ldelta = 0;
+ khm_int32 rv;
+
+ /* find matching creds and update them */
+ for(i=0; i<ncl1; i++)
+ if(cl1[i]) {
+ for(j=0; j<ncl2; j++)
+ if(cl2[j] && kcdb_creds_is_equal((khm_handle) cl1[i], (khm_handle) cl2[j])) {
+ /* they are equivalent. make them equal */
+
+ /* depending on whether any changes were made,
+ update ldelta with the proper bit flag */
+
+ rv = kcdb_cred_update(cl1[i], cl2[j]);
+ if (rv == KHM_ERROR_SUCCESS) {
+ kcdb_credset_update_cred_ref((khm_handle) cs1, (khm_handle) cl1[i]);
+ ldelta |= KCDB_DELTA_MODIFY;
+ }
+
+ cl2[j] = NULL;
+ cl1[i] = NULL;
+ break;
+ }
+ }
+
+ /* all the creds that are left in cl1 need to be removed */
+ for(i=0; i<ncl1; i++)
+ if(cl1[i]) {
+ kcdb_credset_del_cred_ref((khm_handle) cs1, (khm_handle) cl1[i]);
+ cl1[i] = NULL;
+ ldelta |= KCDB_DELTA_DEL;
+ }
+
+ /* all the creds in cl2 need to be added to cs1 */
+ for(j=0; j<ncl2; j++)
+ if(cl2[j]) {
+ /* duplicate the credential and add it if we are adding it to the
+ root credential store. */
+ if(cs1 == kcdb_root_credset) {
+ khm_handle h;
+
+ if(KHM_SUCCEEDED(kcdb_cred_dup((khm_handle) cl2[j], &h))) {
+ kcdb_credset_add_cred((khm_handle) cs1, h, -1);
+ kcdb_cred_release(h);
+ }
+ } else
+ kcdb_credset_add_cred((khm_handle) cs1, cl2[j], -1);
+ cl2[j] = NULL;
+ ldelta |= KCDB_DELTA_ADD;
+ }
+
+ if(delta)
+ *delta = ldelta;
+
+ if((cs1 == kcdb_root_credset) && ldelta) {
+ /* something changed in the root credential set */
+ kmq_post_message(KMSG_CRED,KMSG_CRED_ROOTDELTA,ldelta,NULL);
+ }
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_collect(
+ khm_handle cs_dest,
+ khm_handle cs_src,
+ khm_handle identity,
+ khm_int32 type,
+ khm_int32 * delta)
+{
+ kcdb_credset * cs;
+ kcdb_credset * rcs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred ** r_sel = NULL;
+ kcdb_cred ** c_sel = NULL;
+ int nr_sel, nc_sel;
+ int i;
+
+ if((cs_src && !kcdb_credset_is_credset(cs_src)) ||
+ (cs_dest && !kcdb_credset_is_credset(cs_dest)) ||
+ (cs_src == cs_dest)) /* works because credsets use shared
+ handles */
+ return KHM_ERROR_INVALID_PARM;
+
+ if(identity && !kcdb_is_active_identity(identity))
+ return KHM_ERROR_INVALID_PARM;
+
+ if(cs_src)
+ cs = (kcdb_credset *) cs_src;
+ else
+ cs = kcdb_root_credset;
+
+ if(cs_dest)
+ rcs = (kcdb_credset *) cs_dest;
+ else
+ rcs = kcdb_root_credset;
+
+ if (kcdb_credset_is_sealed(rcs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+ EnterCriticalSection(&(rcs->cs));
+
+ /* enumerate through the root and given credential sets and select
+ the ones we want */
+
+ if(rcs->nclist > 0)
+ r_sel = malloc(sizeof(kcdb_cred *) * rcs->nclist);
+ if(cs->nclist > 0)
+ c_sel = malloc(sizeof(kcdb_cred *) * cs->nclist);
+ nr_sel = 0;
+ nc_sel = 0;
+
+ for(i=0; i<rcs->nclist; i++) {
+ if(rcs->clist[i].cred &&
+ (!identity || rcs->clist[i].cred->identity == identity) &&
+ (type==KCDB_CREDTYPE_ALL || rcs->clist[i].cred->type == type))
+ {
+ r_sel[nr_sel++] = rcs->clist[i].cred;
+ }
+ }
+
+ for(i=0; i<cs->nclist; i++) {
+ if(cs->clist[i].cred &&
+ (!identity || cs->clist[i].cred->identity == identity) &&
+ (type==KCDB_CREDTYPE_ALL || cs->clist[i].cred->type == type))
+ {
+ c_sel[nc_sel++] = cs->clist[i].cred;
+ }
+ }
+
+ rcs->version++;
+
+ code = kcdb_credset_collect_core(
+ rcs,
+ r_sel,
+ nr_sel,
+ cs,
+ c_sel,
+ nc_sel,
+ delta);
+
+ LeaveCriticalSection(&(rcs->cs));
+ LeaveCriticalSection(&(cs->cs));
+
+ if(r_sel)
+ free(r_sel);
+ if(c_sel)
+ free(c_sel);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_collect_filtered(
+ khm_handle cs_dest,
+ khm_handle cs_src,
+ kcdb_cred_filter_func filter,
+ void * rock,
+ khm_int32 * delta)
+{
+ kcdb_credset * cs;
+ kcdb_credset * rcs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_cred ** r_sel = NULL;
+ kcdb_cred ** c_sel = NULL;
+ int nr_sel, nc_sel;
+ int i;
+ khm_int32 cs_f = 0;
+ khm_int32 rcs_f = 0;
+
+ if((cs_src && !kcdb_credset_is_credset(cs_src)) ||
+ (cs_dest && !kcdb_credset_is_credset(cs_dest)) ||
+ (cs_src == cs_dest)) /* works because credsets use shared
+ handles */
+ return KHM_ERROR_INVALID_PARM;
+
+ if(cs_src)
+ cs = (kcdb_credset *) cs_src;
+ else {
+ cs = kcdb_root_credset;
+ cs_f = KCDB_CREDCOLL_FILTER_ROOT;
+ }
+
+ if(cs_dest)
+ rcs = (kcdb_credset *) cs_dest;
+ else {
+ rcs = kcdb_root_credset;
+ rcs_f = KCDB_CREDCOLL_FILTER_ROOT;
+ }
+
+ if (kcdb_credset_is_sealed(rcs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+ EnterCriticalSection(&(rcs->cs));
+
+#ifdef DEBUG
+ assert(!(rcs->flags & KCDB_CREDSET_FLAG_ENUM));
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ if(rcs->nclist)
+ r_sel = malloc(sizeof(kcdb_cred *) * rcs->nclist);
+ if(cs->nclist)
+ c_sel = malloc(sizeof(kcdb_cred *) * cs->nclist);
+ nr_sel = 0;
+ nc_sel = 0;
+
+ rcs->flags |= KCDB_CREDSET_FLAG_ENUM;
+
+ for(i=0; i<rcs->nclist; i++) {
+ if(rcs->clist[i].cred &&
+ (*filter)((khm_handle)rcs->clist[i].cred,
+ KCDB_CREDCOLL_FILTER_DEST | rcs_f,
+ rock))
+ {
+ r_sel[nr_sel++] = rcs->clist[i].cred;
+ }
+ }
+
+ rcs->flags &= ~KCDB_CREDSET_FLAG_ENUM;
+ cs->flags |= KCDB_CREDSET_FLAG_ENUM;
+
+ for(i=0; i<cs->nclist; i++) {
+ if(cs->clist[i].cred && filter((khm_handle)rcs->clist[i].cred, KCDB_CREDCOLL_FILTER_SRC | cs_f, rock))
+ {
+ c_sel[nc_sel++] = cs->clist[i].cred;
+ }
+ }
+
+ cs->flags &= ~KCDB_CREDSET_FLAG_ENUM;
+
+ rcs->version++;
+
+ code = kcdb_credset_collect_core(
+ rcs,
+ r_sel,
+ nr_sel,
+ cs,
+ c_sel,
+ nc_sel,
+ delta);
+
+ LeaveCriticalSection(&(rcs->cs));
+ LeaveCriticalSection(&(cs->cs));
+
+ if(r_sel)
+ free(r_sel);
+ if(c_sel)
+ free(c_sel);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_flush(khm_handle vcredset)
+{
+ int i;
+ kcdb_credset * cs;
+
+ if(!kcdb_credset_is_credset(vcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) vcredset;
+
+ if (kcdb_credset_is_sealed(cs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+
+#ifdef DEBUG
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ for(i=0;i<cs->nclist;i++) {
+ if(cs->clist[i].cred) {
+ kcdb_cred_release((khm_handle) cs->clist[i].cred);
+ }
+ }
+ cs->nclist = 0;
+ LeaveCriticalSection(&(cs->cs));
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_extract(
+ khm_handle destcredset,
+ khm_handle sourcecredset,
+ khm_handle identity,
+ khm_int32 type)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_credset * dest;
+ kcdb_credset * src;
+ int isRoot = 0;
+ khm_size srcSize = 0;
+ int i;
+
+ if(!kcdb_credset_is_credset(destcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ if(sourcecredset) {
+ if(!kcdb_credset_is_credset(sourcecredset))
+ return KHM_ERROR_INVALID_PARM;
+ } else {
+ sourcecredset = kcdb_root_credset;
+ }
+
+ if (sourcecredset == kcdb_root_credset)
+ isRoot = 1;
+
+ src = (kcdb_credset *) sourcecredset;
+ dest = (kcdb_credset *) destcredset;
+
+ if (kcdb_credset_is_sealed(dest))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(src->cs));
+ EnterCriticalSection(&(dest->cs));
+
+#ifdef DEBUG
+ assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) {
+ code = KHM_ERROR_UNKNOWN;
+ goto _exit;
+ }
+
+ kcdb_cred_lock_read();
+
+ for(i=0; i < (int) srcSize; i++) {
+ kcdb_cred * c;
+
+ c = src->clist[i].cred;
+ if(kcdb_cred_is_active_cred((khm_handle) c) &&
+ (!identity || c->identity == identity) &&
+ (type==KCDB_TYPE_INVALID || c->type == type))
+ {
+ if(isRoot) {
+ khm_handle newcred;
+
+ kcdb_cred_unlock_read();
+ kcdb_cred_dup((khm_handle) c, &newcred);
+ kcdb_credset_add_cred(destcredset, newcred, -1);
+ kcdb_cred_release(newcred);
+ kcdb_cred_lock_read();
+ } else {
+ kcdb_cred_unlock_read();
+ kcdb_credset_add_cred(destcredset, (khm_handle) c, -1);
+ kcdb_cred_lock_read();
+ }
+ }
+ }
+
+ kcdb_cred_unlock_read();
+
+_exit:
+ LeaveCriticalSection(&(dest->cs));
+ LeaveCriticalSection(&(src->cs));
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_extract_filtered(
+ khm_handle destcredset,
+ khm_handle sourcecredset,
+ kcdb_cred_filter_func filter,
+ void * rock)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_credset * dest;
+ kcdb_credset * src;
+ int isRoot = 0;
+ khm_size srcSize = 0;
+ int i;
+
+ if(!kcdb_credset_is_credset(destcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ if(sourcecredset) {
+ if(!kcdb_credset_is_credset(sourcecredset))
+ return KHM_ERROR_INVALID_PARM;
+ } else {
+ sourcecredset = kcdb_root_credset;
+ isRoot = 1;
+ }
+
+ src = (kcdb_credset *) sourcecredset;
+ dest = (kcdb_credset *) destcredset;
+
+ if (kcdb_credset_is_sealed(dest))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(src->cs));
+ EnterCriticalSection(&(dest->cs));
+
+#ifdef DEBUG
+ assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) {
+ code = KHM_ERROR_UNKNOWN;
+ goto _exit;
+ }
+
+ kcdb_cred_lock_read();
+
+ dest->flags |= KCDB_CREDSET_FLAG_ENUM;
+
+ for(i=0; i < (int) srcSize; i++) {
+ kcdb_cred * c;
+
+ c = src->clist[i].cred;
+ if(kcdb_cred_is_active_cred((khm_handle) c) &&
+ filter(c, 0, rock))
+ {
+ if(isRoot) {
+ khm_handle newcred;
+
+ kcdb_cred_unlock_read();
+ kcdb_cred_dup((khm_handle) c, &newcred);
+ kcdb_credset_add_cred(destcredset, newcred, -1);
+ kcdb_cred_release(newcred);
+ kcdb_cred_lock_read();
+ } else {
+ kcdb_cred_unlock_read();
+ kcdb_credset_add_cred(destcredset, (khm_handle) c, -1);
+ kcdb_cred_lock_read();
+ }
+ }
+ }
+
+ dest->flags &= ~KCDB_CREDSET_FLAG_ENUM;
+
+ kcdb_cred_unlock_read();
+
+_exit:
+ LeaveCriticalSection(&(dest->cs));
+ LeaveCriticalSection(&(src->cs));
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_apply(khm_handle vcredset, kcdb_cred_apply_func f, void * rock)
+{
+ kcdb_credset * cs;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ int i;
+
+ if(vcredset != NULL && !kcdb_credset_is_credset(vcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ if(vcredset == NULL) {
+ cs = kcdb_root_credset;
+ } else {
+ cs = (kcdb_credset *) vcredset;
+ }
+
+ EnterCriticalSection(&cs->cs);
+
+#ifdef DEBUG
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ cs->flags |= KCDB_CREDSET_FLAG_ENUM;
+
+ for(i=0; i<cs->nclist; i++) {
+ if(!kcdb_cred_is_active_cred(cs->clist[i].cred))
+ continue;
+
+ if(KHM_FAILED(f((khm_handle) cs->clist[i].cred, rock)))
+ break;
+ }
+
+ cs->flags &= ~KCDB_CREDSET_FLAG_ENUM;
+
+ LeaveCriticalSection(&cs->cs);
+
+ if(i<cs->nclist)
+ rv = KHM_ERROR_EXIT;
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_get_cred(
+ khm_handle vcredset,
+ khm_int32 idx,
+ khm_handle * cred)
+{
+ kcdb_credset * cs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+
+ if(!kcdb_credset_is_credset(vcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) vcredset;
+
+ *cred = NULL;
+
+ EnterCriticalSection(&(cs->cs));
+ if(idx < 0 || idx >= cs->nclist)
+ code = KHM_ERROR_OUT_OF_BOUNDS;
+ else if(!cs->clist[idx].cred || !kcdb_cred_is_active_cred((khm_handle) cs->clist[idx].cred)) {
+ code = KHM_ERROR_DELETED;
+ if(cs->clist[idx].cred) {
+ kcdb_cred_release((khm_handle) cs->clist[idx].cred);
+ cs->clist[idx].cred = NULL;
+ }
+ }
+ else {
+ kcdb_cred_hold((khm_handle) cs->clist[idx].cred);
+ *cred = cs->clist[idx].cred;
+ }
+ LeaveCriticalSection(&(cs->cs));
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_find_filtered(
+ khm_handle credset,
+ khm_int32 idx_start,
+ kcdb_cred_filter_func f,
+ void * rock,
+ khm_handle * cred,
+ khm_int32 * idx)
+{
+ kcdb_credset * cs;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ int i;
+
+ if((credset && !kcdb_credset_is_credset(credset)) ||
+ (!f || !cred))
+ return KHM_ERROR_INVALID_PARM;
+
+ if(credset)
+ cs = (kcdb_credset *) credset;
+ else
+ cs = kcdb_root_credset;
+
+ EnterCriticalSection(&cs->cs);
+
+ if(idx_start < 0)
+ i = 0;
+ else
+ i = idx_start + 1;
+
+#ifdef DEBUG
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ cs->flags |= KCDB_CREDSET_FLAG_ENUM;
+
+ for(; i < cs->nclist; i++) {
+ if(kcdb_cred_is_active_cred(cs->clist[i].cred) &&
+ (*f)((khm_handle) cs->clist[i].cred, 0, rock) != 0)
+ break;
+ }
+
+ cs->flags &= ~KCDB_CREDSET_FLAG_ENUM;
+
+ if(i < cs->nclist) {
+ *cred = (khm_handle) cs->clist[i].cred;
+ kcdb_cred_hold(*cred);
+ if(idx)
+ *idx = i;
+ } else {
+ rv = KHM_ERROR_NOT_FOUND;
+ }
+
+ LeaveCriticalSection(&cs->cs);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_find_cred(khm_handle vcredset,
+ khm_handle vcred_src,
+ khm_handle *cred_dest) {
+ kcdb_credset * cs;
+ khm_handle cred = NULL;
+ int idx;
+
+ if (!kcdb_credset_is_credset(vcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ if (!kcdb_cred_is_active_cred(vcred_src))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) vcredset;
+
+ EnterCriticalSection(&cs->cs);
+ for (idx = 0; idx < cs->nclist; idx++) {
+ if (cs->clist[idx].cred &&
+ kcdb_creds_is_equal(vcred_src, cs->clist[idx].cred)) {
+ cred = cs->clist[idx].cred;
+ break;
+ }
+ }
+
+ if (cred)
+ kcdb_cred_hold(cred);
+
+ LeaveCriticalSection(&cs->cs);
+
+ if (cred) {
+ if (cred_dest)
+ *cred_dest = cred;
+ else
+ kcdb_cred_release(cred);
+
+ return KHM_ERROR_SUCCESS;
+ } else {
+ return KHM_ERROR_NOT_FOUND;
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred(
+ khm_handle vcredset,
+ khm_int32 idx)
+{
+ kcdb_credset * cs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+
+ if(!kcdb_credset_is_credset(vcredset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) vcredset;
+
+ if (kcdb_credset_is_sealed(cs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+ if(idx < 0 || idx >= cs->nclist) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ if(cs->clist[idx].cred)
+ kcdb_cred_release((khm_handle) cs->clist[idx].cred);
+
+ if (!(cs->flags & KCDB_CREDSET_FLAG_ENUM)) {
+
+ if(idx + 1 < cs->nclist)
+ memmove(&(cs->clist[idx]),
+ &(cs->clist[idx+1]),
+ sizeof(kcdb_credset_credref) *
+ (cs->nclist - (idx + 1)));
+
+ cs->nclist--;
+ } else {
+ cs->clist[idx].cred = NULL;
+ }
+
+_exit:
+ LeaveCriticalSection(&(cs->cs));
+
+ return code;
+}
+
+khm_int32 kcdb_credset_update_cred_ref(
+ khm_handle credset,
+ khm_handle cred)
+{
+ kcdb_credset * cs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ int i;
+
+ if(!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ EnterCriticalSection(&(cs->cs));
+
+ for(i=0; i<cs->nclist; i++) {
+ if(cs->clist[i].cred == cred)
+ break;
+ }
+
+ if(i<cs->nclist) {
+ cs->clist[i].version = cs->version;
+ } else {
+ code = KHM_ERROR_NOT_FOUND;
+ }
+
+ LeaveCriticalSection(&(cs->cs));
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred_ref(
+ khm_handle credset,
+ khm_handle cred)
+{
+ kcdb_credset * cs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ int i;
+
+ if(!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ if (kcdb_credset_is_sealed(cs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+
+ for(i=0; i<cs->nclist; i++) {
+ if(cs->clist[i].cred == cred)
+ break;
+ }
+
+ if(i<cs->nclist) {
+ code = kcdb_credset_del_cred(credset, i);
+ } else {
+ code = KHM_ERROR_NOT_FOUND;
+ }
+
+ LeaveCriticalSection(&(cs->cs));
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_add_cred(
+ khm_handle credset,
+ khm_handle cred,
+ khm_int32 idx)
+{
+ int new_idx;
+ kcdb_credset * cs;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+
+ if(!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ if (kcdb_credset_is_sealed(cs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+
+ kcdb_credset_buf_assert_size(cs, cs->nclist + 1);
+
+ if(idx < 0 || idx > cs->nclist)
+ new_idx = cs->nclist;
+ else if(idx < cs->nclist){
+#ifdef DEBUG
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+ memmove(&(cs->clist[idx+1]), &(cs->clist[idx]), (cs->nclist - idx)*sizeof(cs->clist[0]));
+ new_idx = idx;
+ } else
+ new_idx = idx;
+
+ kcdb_cred_hold(cred);
+
+ cs->clist[new_idx].cred = (kcdb_cred *) cred;
+ cs->clist[new_idx].version = cs->version;
+ cs->nclist++;
+
+ LeaveCriticalSection(&(cs->cs));
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_get_size(
+ khm_handle credset,
+ khm_size * size)
+{
+ kcdb_credset * cs;
+
+ *size = 0;
+
+ /* we don't rely on this working, since we can't purge a sealed
+ credset, although we can measure its size. */
+ kcdb_credset_purge(credset);
+
+ if (credset == NULL)
+ cs = kcdb_root_credset;
+ else
+ cs = (kcdb_credset *) credset;
+
+ EnterCriticalSection(&(cs->cs));
+ /* while it may seem a bit redundant to get a lock, it ensures that
+ that the size that we return is consistent with the current state
+ of the credential set */
+ *size = cs->nclist;
+ LeaveCriticalSection(&(cs->cs));
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_purge(khm_handle credset)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_credset * cs;
+ int i,j;
+
+ if(!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ if (kcdb_credset_is_sealed(cs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+
+ /* we can't purge a credset while an enumeration operation is in
+ progress. */
+ if (cs->flags & KCDB_CREDSET_FLAG_ENUM) {
+ code = KHM_ERROR_INVALID_OPERATION;
+ goto _exit;
+ }
+
+ for(i=0,j=0; i < cs->nclist; i++) {
+ if(cs->clist[i].cred) {
+ if(!kcdb_cred_is_active_cred((khm_handle) cs->clist[i].cred)) {
+ kcdb_cred_release((khm_handle) cs->clist[i].cred);
+ } else if(i != j) {
+ cs->clist[j++] = cs->clist[i];
+ } else
+ j++;
+ }
+ }
+ cs->nclist = j;
+
+ _exit:
+ LeaveCriticalSection(&(cs->cs));
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_seal(khm_handle credset) {
+ kcdb_credset * cs;
+
+ if (!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ EnterCriticalSection(&cs->cs);
+ cs->seal_count++;
+ LeaveCriticalSection(&cs->cs);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_unseal(khm_handle credset) {
+ kcdb_credset * cs;
+ khm_int32 rv;
+
+ if (!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ EnterCriticalSection(&cs->cs);
+ if (cs->seal_count > 0) {
+ cs->seal_count--;
+ rv = KHM_ERROR_SUCCESS;
+ } else {
+ rv = KHM_ERROR_INVALID_OPERATION;
+ }
+ LeaveCriticalSection(&cs->cs);
+
+ return rv;
+}
+
+
+/* wrapper for qsort and also parameter gobbling FSM. */
+int __cdecl kcdb_creds_comp_wrapper(const void * a, const void * b)
+{
+ static void * rock = NULL;
+ static kcdb_cred_comp_func comp = NULL;
+
+ if(!b) {
+ rock = (void *) a;
+ return 0;
+ }
+
+ if(!a) {
+ comp = (kcdb_cred_comp_func) b;
+ return 0;
+ }
+
+ return comp((khm_handle) ((kcdb_credset_credref *)a)->cred, (khm_handle) ((kcdb_credset_credref *)b)->cred, rock);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credset_sort(
+ khm_handle credset,
+ kcdb_cred_comp_func comp,
+ void * rock)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_credset * cs;
+
+ if(!kcdb_credset_is_credset(credset))
+ return KHM_ERROR_INVALID_PARM;
+
+ cs = (kcdb_credset *) credset;
+
+ if (kcdb_credset_is_sealed(cs))
+ return KHM_ERROR_INVALID_OPERATION;
+
+ EnterCriticalSection(&(cs->cs));
+
+#ifdef DEBUG
+ assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM));
+#endif
+
+ kcdb_creds_comp_wrapper(rock, NULL);
+ kcdb_creds_comp_wrapper(NULL, (void *) comp);
+
+ qsort(cs->clist, cs->nclist, sizeof(kcdb_credset_credref), kcdb_creds_comp_wrapper);
+
+ LeaveCriticalSection(&(cs->cs));
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_cred_comp_generic(
+ khm_handle cred1,
+ khm_handle cred2,
+ void * rock)
+{
+ kcdb_cred_comp_order * o = (kcdb_cred_comp_order *) rock;
+ int i;
+ khm_int32 r = 0;
+ khm_int32 f1, f2;
+ khm_int32 pt;
+
+ for(i=0; i<o->nFields; i++) {
+ if (o->fields[i].order & KCDB_CRED_COMP_INITIAL_FIRST) {
+
+ kcdb_cred_get_flags(cred1, &f1);
+ kcdb_cred_get_flags(cred2, &f2);
+
+ if (((f1 ^ f2) & KCDB_CRED_FLAG_INITIAL) == 0) {
+ kcdb_cred_get_type(cred1, &f1);
+ kcdb_cred_get_type(cred2, &f2);
+ kcdb_identity_get_type(&pt);
+
+ if (f1 == f2)
+ r = 0;
+ else if (f1 == pt)
+ r = -1;
+ else if (f2 == pt)
+ r = 1;
+ else
+ r = 0;
+ } else if (f1 & KCDB_CRED_FLAG_INITIAL)
+ r = -1;
+ else
+ r = 1;
+ } else {
+ r = 0;
+ }
+
+ if (r == 0)
+ r = kcdb_creds_comp_attr(cred1,cred2,o->fields[i].attrib);
+
+ if(r != 0) {
+ if(o->fields[i].order & KCDB_CRED_COMP_DECREASING)
+ r = -r;
+ break;
+ }
+ }
+
+ return r;
+}
diff --git a/src/windows/identity/kcreddb/credset.h b/src/windows/identity/kcreddb/credset.h
new file mode 100644
index 0000000..c192465
--- /dev/null
+++ b/src/windows/identity/kcreddb/credset.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_CREDSET_H
+#define __KHIMAIRA_KCDB_CREDSET_H
+
+/* credset */
+
+typedef struct kcdb_credset_credref_t {
+ khm_int32 version;
+ kcdb_cred * cred;
+} kcdb_credset_credref;
+
+typedef struct kcdb_credset_t {
+ khm_int32 magic;
+ khm_int32 flags;
+ CRITICAL_SECTION cs;
+
+ kcdb_credset_credref * clist;
+ khm_int32 nc_clist; /* total capacity */
+ khm_int32 nclist; /* current load */
+
+ khm_int32 version; /* data version */
+
+ khm_int32 seal_count; /* number of seals applied to the
+ credset */
+
+ struct kcdb_credset_t * next;
+ struct kcdb_credset_t * prev;
+} kcdb_credset;
+
+#define KCDB_CREDSET_MAGIC 0x63a84f8b
+
+#define KCDB_CREDSET_FLAG_ROOT 1
+
+/* the credset is in the process of being enumerated */
+#define KCDB_CREDSET_FLAG_ENUM 2
+
+#define kcdb_credset_is_credset(c) ((c) && ((kcdb_credset *)c)->magic == KCDB_CREDSET_MAGIC)
+
+#define kcdb_credset_is_sealed(c) ((c)->seal_count != 0)
+
+#define KCDB_CREDSET_INITIAL_SIZE 1024
+#define KCDB_CREDSET_GROWTH_FACTOR 1024
+
+void kcdb_credset_init(void);
+void kcdb_credset_exit(void);
+khm_int32 kcdb_credset_update_cred_ref(
+ khm_handle credset,
+ khm_handle cred);
+
+#endif
diff --git a/src/windows/identity/kcreddb/credtype.c b/src/windows/identity/kcreddb/credtype.c
new file mode 100644
index 0000000..dc2b7b8
--- /dev/null
+++ b/src/windows/identity/kcreddb/credtype.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+
+CRITICAL_SECTION cs_credtype;
+kcdb_credtype_i ** kcdb_credtype_tbl = NULL;
+kcdb_credtype_i * kcdb_credtypes = NULL;
+
+void kcdb_credtype_init(void)
+{
+ InitializeCriticalSection(&cs_credtype);
+ kcdb_credtypes = NULL;
+ kcdb_credtype_tbl = malloc(sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1));
+ ZeroMemory(kcdb_credtype_tbl, sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1));
+}
+
+void kcdb_credtype_exit(void)
+{
+ /*TODO:Free up the cred types */
+ free(kcdb_credtype_tbl);
+ DeleteCriticalSection(&cs_credtype);
+}
+
+/* Called with cs_credtype held */
+void kcdb_credtype_check_and_delete(khm_int32 id)
+{
+ kcdb_credtype_i * ict;
+ ict = kcdb_credtype_tbl[id];
+ if(!ict)
+ return;
+
+ if((ict->flags & KCDB_CTI_FLAG_DELETED) &&
+ !ict->refcount)
+ {
+ kcdb_credtype_tbl[id] = NULL;
+ LDELETE(&kcdb_credtypes, ict);
+
+ free(ict->ct.name);
+ if(ict->ct.short_desc)
+ free(ict->ct.short_desc);
+ if(ict->ct.long_desc)
+ free(ict->ct.long_desc);
+ if(ict->ct.sub)
+ kmq_delete_subscription(ict->ct.sub);
+
+ free(ict);
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_register(kcdb_credtype * type, khm_int32 * new_id)
+{
+ khm_int32 id;
+ kcdb_credtype_i * ict;
+ size_t cb_name;
+ size_t cb_short_desc;
+ size_t cb_long_desc;
+ int i;
+
+ if(!type)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(type->id >= KCDB_CREDTYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(type->name) {
+ if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cb_name)))
+ return KHM_ERROR_TOO_LONG;
+ cb_name += sizeof(wchar_t);
+ } else
+ return KHM_ERROR_INVALID_PARM;
+
+ if(type->short_desc) {
+ if(FAILED(StringCbLength(type->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc)))
+ return KHM_ERROR_TOO_LONG;
+ cb_short_desc += sizeof(wchar_t);
+ } else
+ cb_short_desc = 0;
+
+ if(type->long_desc) {
+ if(FAILED(StringCbLength(type->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc)))
+ return KHM_ERROR_TOO_LONG;
+ cb_long_desc += sizeof(wchar_t);
+ } else
+ cb_long_desc = 0;
+
+ if(type->sub == NULL)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+
+ if(type->id < 0) {
+ if(KHM_FAILED(kcdb_credtype_get_next_free_id(&id))) {
+ LeaveCriticalSection(&cs_credtype);
+ return KHM_ERROR_NO_RESOURCES;
+ }
+ }
+ else
+ id = type->id;
+
+ if(kcdb_credtype_tbl[id]) {
+ LeaveCriticalSection(&cs_credtype);
+ return KHM_ERROR_DUPLICATE;
+ }
+
+ for(i=0;i<=KCDB_CREDTYPE_MAX_ID;i++) {
+ if(kcdb_credtype_tbl[i] && !wcscmp(kcdb_credtype_tbl[i]->ct.name, type->name)) {
+ LeaveCriticalSection(&cs_credtype);
+ return KHM_ERROR_DUPLICATE;
+ }
+ }
+
+ ict = malloc(sizeof(kcdb_credtype_i));
+ ZeroMemory(ict, sizeof(kcdb_credtype_i));
+
+ ict->ct.name = malloc(cb_name);
+ StringCbCopy(ict->ct.name, cb_name, type->name);
+
+ if(cb_short_desc) {
+ ict->ct.short_desc = malloc(cb_short_desc);
+ StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc);
+ }
+
+ if(cb_long_desc) {
+ ict->ct.long_desc = malloc(cb_long_desc);
+ StringCbCopy(ict->ct.long_desc, cb_long_desc, type->long_desc);
+ }
+
+ ict->ct.id = id;
+
+ ict->ct.icon = type->icon;
+
+ ict->ct.sub = type->sub;
+
+ kcdb_credtype_tbl[id] = ict;
+
+ LPUSH(&kcdb_credtypes, ict);
+
+ LeaveCriticalSection(&cs_credtype);
+
+ kcdb_credtype_post_message(KCDB_OP_INSERT, &(ict->ct));
+
+ if (new_id)
+ *new_id = id;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_get_info(
+ khm_int32 id,
+ kcdb_credtype ** type)
+{
+ int found = 0;
+
+ if(id < 0 || id > KCDB_CREDTYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ if(kcdb_credtype_tbl[id] &&
+ !(kcdb_credtype_tbl[id]->flags & KCDB_CTI_FLAG_DELETED))
+ {
+ found = 1;
+ if(type) {
+ *type = &(kcdb_credtype_tbl[id]->ct);
+ kcdb_credtype_hold(kcdb_credtype_tbl[id]);
+ }
+ } else {
+ if(type)
+ *type = NULL;
+ }
+ LeaveCriticalSection(&cs_credtype);
+
+ if(found)
+ return KHM_ERROR_SUCCESS;
+ else
+ return KHM_ERROR_NOT_FOUND;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_release_info(kcdb_credtype * type)
+{
+ kcdb_credtype_i * ict;
+
+ if(!type)
+ return KHM_ERROR_INVALID_PARM;
+
+ ict = (kcdb_credtype_i *) type;
+ return kcdb_credtype_release(ict);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_unregister(khm_int32 id)
+{
+ kcdb_credtype_i * ict;
+
+ if(id < 0 || id > KCDB_CREDTYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ ict = kcdb_credtype_tbl[id];
+ ict->flags |= KCDB_CTI_FLAG_DELETED;
+ kcdb_credtype_check_and_delete(id);
+ LeaveCriticalSection(&cs_credtype);
+
+ //kcdb_credtype_post_message(KCDB_OP_DELETE, &(ict->ct));
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_handle KHMAPI kcdb_credtype_get_sub(khm_int32 id)
+{
+ kcdb_credtype_i * t;
+ khm_handle s;
+
+ if(id < 0 || id > KCDB_CREDTYPE_MAX_ID)
+ return NULL;
+
+ EnterCriticalSection(&cs_credtype);
+ t = kcdb_credtype_tbl[id];
+ if(t)
+ s = t->ct.sub;
+ else
+ s = NULL;
+ LeaveCriticalSection(&cs_credtype);
+
+ return s;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_describe(
+ khm_int32 id,
+ wchar_t * buf,
+ khm_size * cbbuf,
+ khm_int32 flags)
+{
+ size_t s;
+ size_t maxs;
+ wchar_t * str;
+ kcdb_credtype_i * t;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ t = kcdb_credtype_tbl[id];
+ if(t) {
+ if(flags & KCDB_TS_SHORT) {
+ str = (t->ct.short_desc)?t->ct.short_desc:t->ct.name;
+ maxs = (t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME;
+ } else {
+ str = (t->ct.long_desc)?t->ct.long_desc:((t->ct.short_desc)?t->ct.short_desc:t->ct.name);
+ maxs = (t->ct.long_desc)?KCDB_MAXCB_LONG_DESC:((t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME);
+ }
+ StringCbLength(str, maxs, &s);
+ s += sizeof(wchar_t);
+ if(!buf || *cbbuf < s) {
+ *cbbuf = s;
+ rv = KHM_ERROR_TOO_LONG;
+ } else {
+#pragma warning(push)
+#pragma warning(disable:4995)
+ wcscpy(buf, str); /* str is one of the string fields in t->ct which has
+ been validated when the type was registered. */
+#pragma warning(pop)
+ *cbbuf = s;
+ }
+ } else {
+ if(buf && *cbbuf > 0)
+ *buf = L'\0';
+ *cbbuf = 0;
+ rv = KHM_ERROR_NOT_FOUND;
+ }
+ LeaveCriticalSection(&cs_credtype);
+
+ return rv;
+}
+
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_get_name(
+ khm_int32 id,
+ wchar_t * buf,
+ khm_size * cbbuf)
+{
+ size_t s;
+ kcdb_credtype_i * t;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ t = kcdb_credtype_tbl[id];
+ if(t) {
+ StringCbLength(t->ct.name, KCDB_MAXCB_NAME, &s);
+ s += sizeof(wchar_t);
+ if(!buf || *cbbuf < s) {
+ *cbbuf = s;
+ rv = KHM_ERROR_TOO_LONG;
+ } else {
+#pragma warning(push)
+#pragma warning(disable: 4995)
+ wcscpy(buf, t->ct.name); /* t->ct.name was validated when the type was registered */
+#pragma warning(pop)
+ *cbbuf = s;
+ }
+ } else {
+ *cbbuf = 0;
+ rv = KHM_ERROR_NOT_FOUND;
+ }
+ LeaveCriticalSection(&cs_credtype);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_credtype_get_id(
+ wchar_t * name,
+ khm_int32 * id)
+{
+ int i;
+
+ *id = 0;
+ if(!name)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) {
+ if(kcdb_credtype_tbl[i] && !wcscmp(name, kcdb_credtype_tbl[i]->ct.name))
+ break;
+ }
+ LeaveCriticalSection(&cs_credtype);
+
+ if(i <= KCDB_CREDTYPE_MAX_ID) {
+ *id = i;
+ return KHM_ERROR_SUCCESS;
+ } else
+ return KHM_ERROR_NOT_FOUND;
+}
+
+khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id)
+{
+ int i;
+
+ EnterCriticalSection(&cs_credtype);
+ for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) {
+ if(!kcdb_credtype_tbl[i])
+ break;
+ }
+ LeaveCriticalSection(&cs_credtype);
+
+ if(i <= KCDB_CREDTYPE_MAX_ID) {
+ *id = i;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *id = -1;
+ return KHM_ERROR_NO_RESOURCES;
+ }
+}
+
+khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict) {
+
+ if(!ict)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ ict->refcount++;
+ LeaveCriticalSection(&cs_credtype);
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict) {
+
+ if(!ict)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_credtype);
+ ict->refcount--;
+ kcdb_credtype_check_and_delete(ict->ct.id);
+ LeaveCriticalSection(&cs_credtype);
+ return KHM_ERROR_SUCCESS;
+}
+
+void kcdb_credtype_msg_completion(kmq_message * m)
+{
+ kcdb_credtype_release((kcdb_credtype_i *) m->vparam);
+}
+
+void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type)
+{
+ kcdb_credtype_hold((kcdb_credtype_i *) type);
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_CREDTYPE, op, (void *) type);
+}
diff --git a/src/windows/identity/kcreddb/credtype.h b/src/windows/identity/kcreddb/credtype.h
new file mode 100644
index 0000000..6e46db3
--- /dev/null
+++ b/src/windows/identity/kcreddb/credtype.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_CREDTYPE_H
+#define __KHIMAIRA_KCDB_CREDTYPE_H
+
+/* credtype */
+typedef struct kcdb_credtype_i_t {
+ kcdb_credtype ct;
+ khm_int32 refcount;
+ khm_int32 flags;
+
+ struct kcdb_credtype_i_t * next;
+ struct kcdb_credtype_i_t * prev;
+} kcdb_credtype_i;
+
+#define KCDB_CTI_FLAG_DELETED 8
+
+extern CRITICAL_SECTION cs_credtype;
+extern kcdb_credtype_i * kcdb_credtypes;
+extern kcdb_credtype_i ** kcdb_credtype_tbl;
+
+void kcdb_credtype_init(void);
+void kcdb_credtype_exit(void);
+void kcdb_credtype_check_and_delete(khm_int32 id);
+khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict);
+khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict);
+void kcdb_credtype_msg_completion(kmq_message * m);
+void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type);
+khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id);
+
+#endif \ No newline at end of file
diff --git a/src/windows/identity/kcreddb/identity.c b/src/windows/identity/kcreddb/identity.c
new file mode 100644
index 0000000..d6ae129
--- /dev/null
+++ b/src/windows/identity/kcreddb/identity.c
@@ -0,0 +1,1537 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+#include<assert.h>
+
+CRITICAL_SECTION cs_ident;
+hashtable * kcdb_identities_namemap = NULL;
+khm_int32 kcdb_n_identities = 0;
+kcdb_identity * kcdb_identities = NULL;
+kcdb_identity * kcdb_def_identity = NULL;
+khm_handle kcdb_ident_sub = NULL; /* identity provider */
+khm_int32 kcdb_ident_cred_type = KCDB_CREDTYPE_INVALID;
+/* primary credentials type */
+khm_ui_4 kcdb_ident_refresh_cycle = 0;
+khm_boolean kcdb_checked_config = FALSE;
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_provider(khm_handle sub)
+{
+ EnterCriticalSection(&cs_ident);
+ if (sub != kcdb_ident_sub) {
+ if(kcdb_ident_sub != NULL) {
+ kmq_post_sub_msg(kcdb_ident_sub,
+ KMSG_IDENT,
+ KMSG_IDENT_EXIT,
+ 0,
+ 0);
+ kmq_delete_subscription(kcdb_ident_sub);
+ }
+ kcdb_ident_sub = sub;
+
+ if (kcdb_ident_sub)
+ kmq_post_sub_msg(kcdb_ident_sub,
+ KMSG_IDENT,
+ KMSG_IDENT_INIT,
+ 0,
+ 0);
+ }
+ LeaveCriticalSection(&cs_ident);
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_provider(khm_handle * sub)
+{
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL)
+ rv = KHM_ERROR_SUCCESS;
+ else
+ rv = KHM_ERROR_NOT_FOUND;
+ if(sub != NULL)
+ *sub = kcdb_ident_sub;
+ LeaveCriticalSection(&cs_ident);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_type(khm_int32 cred_type)
+{
+ EnterCriticalSection(&cs_ident);
+ kcdb_ident_cred_type = cred_type;
+ LeaveCriticalSection(&cs_ident);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_type(khm_int32 * ptype)
+{
+ if (!ptype)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ *ptype = kcdb_ident_cred_type;
+ LeaveCriticalSection(&cs_ident);
+
+ if (*ptype >= 0)
+ return KHM_ERROR_SUCCESS;
+ else
+ return KHM_ERROR_NOT_FOUND;
+}
+
+/* message completion routine */
+void
+kcdbint_ident_msg_completion(kmq_message * m) {
+ kcdb_identity_release(m->vparam);
+}
+
+void
+kcdbint_ident_add_ref(const void * key, void * vid) {
+ /* References in the hashtable are not refcounted */
+
+ // kcdb_identity_hold(vid);
+}
+
+void
+kcdbint_ident_del_ref(const void * key, void * vid) {
+ /* References in the hashtable are not refcounted */
+
+ // kcdb_identity_release(vid);
+}
+
+void
+kcdbint_ident_init(void) {
+ InitializeCriticalSection(&cs_ident);
+ kcdb_identities_namemap = hash_new_hashtable(
+ KCDB_IDENT_HASHTABLE_SIZE,
+ hash_string,
+ hash_string_comp,
+ kcdbint_ident_add_ref,
+ kcdbint_ident_del_ref);
+}
+
+void
+kcdbint_ident_exit(void) {
+ EnterCriticalSection(&cs_ident);
+ hash_del_hashtable(kcdb_identities_namemap);
+ LeaveCriticalSection(&cs_ident);
+ DeleteCriticalSection(&cs_ident);
+}
+
+KHMEXP khm_boolean KHMAPI
+kcdb_identity_is_valid_name(const wchar_t * name)
+{
+ khm_int32 rv;
+
+ /* special case. Note since the string we are comparing with is
+ of a known length we don't need to check the length of name. */
+ if (!wcscmp(name, L"_Schema"))
+ return FALSE;
+
+ rv = kcdb_identpro_validate_name(name);
+
+ if(rv == KHM_ERROR_NO_PROVIDER ||
+ rv == KHM_ERROR_NOT_IMPLEMENTED)
+ return TRUE;
+ else
+ return KHM_SUCCEEDED(rv);
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_create(const wchar_t *name,
+ khm_int32 flags,
+ khm_handle * result) {
+ kcdb_identity * id;
+ kcdb_identity * id_tmp;
+ size_t namesize;
+
+ if(!result || !name)
+ return KHM_ERROR_INVALID_PARM;
+
+ *result = NULL;
+
+ /* is it there already? */
+ EnterCriticalSection(&cs_ident);
+ id = hash_lookup(kcdb_identities_namemap, (void *) name);
+ if(id)
+ kcdb_identity_hold((khm_handle) id);
+ LeaveCriticalSection(&cs_ident);
+
+ if(id) {
+ *result = (khm_handle) id;
+ return KHM_ERROR_SUCCESS;
+ } else if(!(flags & KCDB_IDENT_FLAG_CREATE)) {
+ return KHM_ERROR_NOT_FOUND;
+ }
+
+ flags &= ~KCDB_IDENT_FLAG_CREATE;
+
+ /* nope. create it */
+ if((flags & ~KCDB_IDENT_FLAGMASK_RDWR) ||
+ (flags & (KCDB_IDENT_FLAG_DEFAULT |
+ KCDB_IDENT_FLAG_SEARCHABLE))) {
+ /* can't specify this flag in create */
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(!kcdb_identity_is_valid_name(name)) {
+ return KHM_ERROR_INVALID_NAME;
+ }
+
+ /* we expect the following will succeed since the above
+ test passed */
+ StringCbLength(name, KCDB_IDENT_MAXCB_NAME, &namesize);
+ namesize += sizeof(wchar_t);
+
+ id = malloc(sizeof(kcdb_identity));
+ ZeroMemory(id, sizeof(kcdb_identity));
+ id->magic = KCDB_IDENT_MAGIC;
+ id->name = malloc(namesize);
+ StringCbCopy(id->name, namesize, name);
+
+ id->flags = (flags & KCDB_IDENT_FLAGMASK_LOCAL);
+ id->flags |= KCDB_IDENT_FLAG_ACTIVE;
+ LINIT(id);
+
+ EnterCriticalSection(&cs_ident);
+ id_tmp = hash_lookup(kcdb_identities_namemap, (void *) id->name);
+ if(id_tmp) {
+ /* lost a race */
+ kcdb_identity_hold((khm_handle) id_tmp);
+ *result = (khm_handle) id_tmp;
+
+ free(id->name);
+ free(id);
+
+ id = NULL;
+ } else {
+ khm_handle h_cfg;
+
+ kcdb_identity_hold((khm_handle) id);
+ hash_add(kcdb_identities_namemap,
+ (void *) id->name,
+ (void *) id);
+ LPUSH(&kcdb_identities, id);
+
+ if(KHM_SUCCEEDED(kcdb_identity_get_config((khm_handle) id,
+ 0,
+ &h_cfg))) {
+ /* don't need to set the KCDB_IDENT_FLAG_CONFIG flags
+ since kcdb_identity_get_conifg() sets it for us. */
+ khm_int32 sticky;
+
+ if (KHM_SUCCEEDED(khc_read_int32(h_cfg, L"Sticky", &sticky)) &&
+ sticky) {
+ id->flags |= KCDB_IDENT_FLAG_STICKY;
+ }
+
+ khc_close_space(h_cfg);
+ }
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(id != NULL) {
+ *result = (khm_handle) id;
+
+ kcdb_identpro_notify_create((khm_handle) id);
+
+ kcdbint_ident_post_message(KCDB_OP_INSERT, id);
+ }
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_delete(khm_handle vid) {
+ kcdb_identity * id;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+
+ EnterCriticalSection(&cs_ident);
+ if(!kcdb_is_identity(vid)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ id = (kcdb_identity *) vid;
+
+ if (kcdb_is_active_identity(vid)) {
+
+ id->flags &= ~KCDB_IDENT_FLAG_ACTIVE;
+
+ hash_del(kcdb_identities_namemap, (void *) id->name);
+
+ LeaveCriticalSection(&cs_ident);
+
+ kcdbint_ident_post_message(KCDB_OP_DELETE, id);
+
+ /* Once everybody finishes dealing with the identity deletion,
+ we will get called again. */
+ return KHM_ERROR_SUCCESS;
+ } else if (id->refcount == 0) {
+ /* If the identity is not active, it is not in the hashtable
+ either */
+ LDELETE(&kcdb_identities, id);
+
+ if (id->name)
+ free(id->name);
+ free(id);
+ }
+ /* else, we have an identity that is not active, but has
+ outstanding references. We have to wait until those references
+ are freed. Once they are released, kcdb_identity_delete() will
+ be called again. */
+
+#if 0
+ EnterCriticalSection(&cs_ident);
+ if(id->refcount == 0) {
+ /*TODO: free up the identity */
+ }
+#endif
+ _exit:
+ LeaveCriticalSection(&cs_ident);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_flags(khm_handle vid,
+ khm_int32 flag) {
+ kcdb_identity * id;
+ khm_int32 oldflags;
+ khm_int32 newflags;
+ khm_int32 delta = 0;
+ khm_int32 rv;
+
+ if(!kcdb_is_active_identity(vid))
+ return KHM_ERROR_INVALID_PARM;
+
+ id = (kcdb_identity *) vid;
+
+ if((flag & ~(KCDB_IDENT_FLAGMASK_RDWR | KCDB_IDENT_FLAG_INVERT)) ||
+ ((flag & KCDB_IDENT_FLAG_INVALID) && (flag & KCDB_IDENT_FLAG_VALID)))
+ return KHM_ERROR_INVALID_PARM;
+
+ if(flag & KCDB_IDENT_FLAG_DEFAULT) {
+ /* kcdb_identity_set_default already does checking for
+ redundant transitions */
+ rv = kcdb_identity_set_default((flag & KCDB_IDENT_FLAG_INVERT)?NULL: vid);
+
+ if(KHM_FAILED(rv))
+ return rv;
+
+ flag &= ~KCDB_IDENT_FLAG_DEFAULT;
+ }
+
+ if(flag & KCDB_IDENT_FLAG_SEARCHABLE) {
+ if(flag & KCDB_IDENT_FLAG_INVERT) {
+ EnterCriticalSection(&cs_ident);
+ if(id->flags & KCDB_IDENT_FLAG_SEARCHABLE) {
+ LeaveCriticalSection(&cs_ident);
+ rv = kcdb_identpro_set_searchable(vid, FALSE);
+ EnterCriticalSection(&cs_ident);
+ if(rv == KHM_ERROR_NO_PROVIDER ||
+ KHM_SUCCEEDED(rv)) {
+ id->flags &= ~KCDB_IDENT_FLAG_SEARCHABLE;
+ delta |= KCDB_IDENT_FLAG_SEARCHABLE;
+ }
+ }
+ LeaveCriticalSection(&cs_ident);
+ } else {
+ EnterCriticalSection(&cs_ident);
+ if(!(id->flags & KCDB_IDENT_FLAG_SEARCHABLE)) {
+ LeaveCriticalSection(&cs_ident);
+ rv = kcdb_identpro_set_searchable(vid, TRUE);
+ EnterCriticalSection(&cs_ident);
+ if(rv == KHM_ERROR_NO_PROVIDER ||
+ KHM_SUCCEEDED(rv)) {
+ id->flags |= KCDB_IDENT_FLAG_SEARCHABLE;
+ delta |= KCDB_IDENT_FLAG_SEARCHABLE;
+ }
+ }
+ LeaveCriticalSection(&cs_ident);
+ }
+
+ flag &= ~KCDB_IDENT_FLAG_SEARCHABLE;
+ }
+
+ /* deal with every other flag */
+
+ EnterCriticalSection(&cs_ident);
+ oldflags = id->flags;
+ if(flag & KCDB_IDENT_FLAG_INVERT) {
+ flag &= ~KCDB_IDENT_FLAG_INVERT;
+ id->flags &= ~flag;
+ } else {
+ id->flags |= flag;
+
+ if(flag & KCDB_IDENT_FLAG_VALID)
+ id->flags &= ~KCDB_IDENT_FLAG_INVALID;
+ if(flag & KCDB_IDENT_FLAG_INVALID)
+ id->flags &= ~KCDB_IDENT_FLAG_VALID;
+ }
+ newflags = id->flags;
+ LeaveCriticalSection(&cs_ident);
+ delta |= newflags ^ oldflags;
+
+ if((delta & KCDB_IDENT_FLAG_HIDDEN)) {
+ kcdbint_ident_post_message(
+ (newflags & KCDB_IDENT_FLAG_HIDDEN)?KCDB_OP_HIDE:KCDB_OP_UNHIDE,
+ vid);
+ }
+
+ if((delta & KCDB_IDENT_FLAG_SEARCHABLE)) {
+ kcdbint_ident_post_message(
+ (newflags & KCDB_IDENT_FLAG_SEARCHABLE)?KCDB_OP_SETSEARCH:KCDB_OP_UNSETSEARCH,
+ vid);
+ }
+
+ if(delta != 0)
+ kcdbint_ident_post_message(KCDB_OP_MODIFY, vid);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_flags(khm_handle vid,
+ khm_int32 * flags) {
+ kcdb_identity * id;
+
+ *flags = 0;
+
+ if(!kcdb_is_active_identity(vid))
+ return KHM_ERROR_INVALID_PARM;
+
+ id = (kcdb_identity *) vid;
+
+ *flags = id->flags;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_name(khm_handle vid,
+ wchar_t * buffer,
+ khm_size * pcbsize) {
+ size_t namesize;
+ kcdb_identity * id;
+
+ if(!kcdb_is_active_identity(vid) || !pcbsize)
+ return KHM_ERROR_INVALID_PARM;
+
+ id = (kcdb_identity *) vid;
+
+ if(FAILED(StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &namesize)))
+ return KHM_ERROR_UNKNOWN;
+
+ namesize += sizeof(wchar_t);
+
+ if(!buffer || namesize > *pcbsize) {
+ *pcbsize = namesize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *pcbsize, id->name);
+ *pcbsize = namesize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_default(khm_handle * pvid) {
+ khm_handle def;
+
+ if (pvid == NULL)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ def = kcdb_def_identity;
+ if (def != NULL)
+ kcdb_identity_hold(def);
+ LeaveCriticalSection(&cs_ident);
+
+ *pvid = def;
+
+ if (def != NULL)
+ return KHM_ERROR_SUCCESS;
+ else
+ return KHM_ERROR_NOT_FOUND;
+}
+
+static khm_int32
+kcdbint_ident_set_default(khm_handle vid,
+ khm_boolean invoke_identpro) {
+ kcdb_identity * new_def;
+ kcdb_identity * old_def;
+ khm_int32 rv;
+
+ if(vid != NULL && !kcdb_is_active_identity(vid))
+ return KHM_ERROR_INVALID_PARM;
+
+ new_def = (kcdb_identity *)vid;
+
+ if(new_def != NULL && (new_def->flags & KCDB_IDENT_FLAG_DEFAULT))
+ return KHM_ERROR_SUCCESS;
+
+ if(new_def == NULL && kcdb_def_identity == NULL)
+ return KHM_ERROR_SUCCESS;
+
+ /* first check with the identity provider if this operation
+ is permitted. */
+ if (invoke_identpro) {
+ rv = kcdb_identpro_set_default(vid);
+ if(rv != KHM_ERROR_NO_PROVIDER && KHM_FAILED(rv))
+ return rv;
+ }
+
+ EnterCriticalSection(&cs_ident);
+
+ old_def = kcdb_def_identity;
+ kcdb_def_identity = new_def;
+
+ if(old_def != new_def) {
+ if(old_def) {
+ old_def->flags &= ~KCDB_IDENT_FLAG_DEFAULT;
+ kcdb_identity_release((khm_handle) old_def);
+ }
+
+ if(new_def) {
+ new_def->flags |= KCDB_IDENT_FLAG_DEFAULT;
+ kcdb_identity_hold((khm_handle) new_def);
+ }
+
+ LeaveCriticalSection(&cs_ident);
+
+ if (invoke_identpro)
+ kcdbint_ident_post_message(KCDB_OP_NEW_DEFAULT, new_def);
+ } else {
+ LeaveCriticalSection(&cs_ident);
+ }
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_default(khm_handle vid) {
+ return kcdbint_ident_set_default(vid, TRUE);
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_default_int(khm_handle vid) {
+ return kcdbint_ident_set_default(vid, FALSE);
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_config(khm_handle vid,
+ khm_int32 flags,
+ khm_handle * result) {
+ khm_handle hkcdb;
+ khm_handle hidents = NULL;
+ khm_handle hident = NULL;
+ khm_int32 rv;
+ kcdb_identity * id;
+
+ if(kcdb_is_active_identity(vid)) {
+ id = (kcdb_identity *) vid;
+ } else {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ hkcdb = kcdb_get_config();
+ if(hkcdb) {
+ rv = khc_open_space(hkcdb, L"Identity", 0, &hidents);
+ if(KHM_FAILED(rv))
+ goto _exit;
+
+ rv = khc_open_space(hidents,
+ id->name,
+ flags | KCONF_FLAG_NOPARSENAME,
+ &hident);
+
+ if(KHM_FAILED(rv))
+ goto _exit;
+
+ EnterCriticalSection(&cs_ident);
+ id->flags |= KCDB_IDENT_FLAG_CONFIG;
+ LeaveCriticalSection(&cs_ident);
+
+ *result = hident;
+ } else
+ rv = KHM_ERROR_UNKNOWN;
+
+_exit:
+ if(hidents)
+ khc_close_space(hidents);
+ if(hkcdb)
+ khc_close_space(hkcdb);
+ return rv;
+}
+
+/*! \note cs_ident must be available. */
+void
+kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id) {
+ kcdb_identity_hold(id);
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_IDENT, op, (void *) id);
+}
+
+/*! \note cs_ident must be available. */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_hold(khm_handle vid) {
+ kcdb_identity * id;
+ if(kcdb_is_active_identity(vid)) {
+ id = vid;
+ InterlockedIncrement(&(id->refcount));
+ } else
+ return KHM_ERROR_INVALID_PARM;
+ return ERROR_SUCCESS;
+}
+
+/*! \note cs_ident must be available. */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_release(khm_handle vid) {
+ kcdb_identity * id;
+ khm_int32 refcount;
+ if(kcdb_is_identity(vid)) {
+ id = vid;
+ refcount = InterlockedDecrement(&(id->refcount));
+ if(refcount == 0) {
+ EnterCriticalSection(&cs_ident);
+ /* We only delete identities which do not have a
+ configuration. */
+ if (id->refcount == 0 &&
+ !(id->flags & KCDB_IDENT_FLAG_CONFIG))
+ kcdb_identity_delete(vid);
+ LeaveCriticalSection(&cs_ident);
+ }
+ } else
+ return KHM_ERROR_INVALID_PARM;
+ return ERROR_SUCCESS;
+}
+
+struct kcdb_idref_result {
+ kcdb_identity * ident;
+ khm_int32 flags;
+ khm_size count;
+};
+
+static khm_int32 KHMAPI
+kcdbint_idref_proc(khm_handle cred, void * r) {
+ khm_handle vid;
+ struct kcdb_idref_result *result;
+ khm_int32 flags;
+
+ result = (struct kcdb_idref_result *) r;
+
+ if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, &vid))) {
+ if (result->ident == (kcdb_identity *) vid) {
+ result->count++;
+ kcdb_cred_get_flags(cred, &flags);
+
+ if (flags & KCDB_CRED_FLAG_RENEWABLE) {
+ result->flags |= KCDB_IDENT_FLAG_CRED_RENEW;
+ if (flags & KCDB_CRED_FLAG_INITIAL) {
+ result->flags |= KCDB_IDENT_FLAG_RENEWABLE;
+ }
+ }
+
+ if (flags & KCDB_CRED_FLAG_EXPIRED) {
+ result->flags |= KCDB_IDENT_FLAG_CRED_EXP;
+ if (flags & KCDB_CRED_FLAG_INITIAL) {
+ result->flags |= KCDB_IDENT_FLAG_EXPIRED;
+ }
+ }
+
+ if (flags & KCDB_CRED_FLAG_INITIAL) {
+ result->flags |= KCDB_IDENT_FLAG_VALID;
+ }
+ }
+
+ kcdb_identity_release(vid);
+ }
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_refresh(khm_handle vid) {
+ kcdb_identity * ident;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ struct kcdb_idref_result result;
+ khm_int32 flags;
+
+ EnterCriticalSection(&cs_ident);
+
+ if (!kcdb_is_active_identity(vid)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ ident = (kcdb_identity *) vid;
+
+ result.ident = ident;
+ result.flags = 0;
+ result.count = 0;
+
+ kcdb_credset_apply(NULL, kcdbint_idref_proc, &result);
+
+ if (result.count == 0)
+ result.flags |= KCDB_IDENT_FLAG_EMPTY;
+
+ kcdb_identity_set_flags(vid, result.flags);
+ kcdb_identity_get_flags(vid, &flags);
+ flags &= KCDB_IDENT_FLAGMASK_RDWR;
+ flags &= ~(KCDB_IDENT_FLAG_DEFAULT |
+ KCDB_IDENT_FLAG_SEARCHABLE);
+ flags ^= result.flags;
+ if (flags != 0)
+ kcdb_identity_set_flags(vid, flags | KCDB_IDENT_FLAG_INVERT);
+
+ ident->refresh_cycle = kcdb_ident_refresh_cycle;
+
+ _exit:
+ LeaveCriticalSection(&cs_ident);
+
+ if (code == 0)
+ code = kcdb_identpro_update(vid);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_refresh_all(void) {
+ kcdb_identity * ident;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ int hit_count;
+
+ EnterCriticalSection(&cs_ident);
+
+ kcdb_ident_refresh_cycle++;
+
+ /* The do-while loop is here to account for race conditions. We
+ release cs_ident in the for loop, so we don't actually have a
+ guarantee that we traversed the whole identity list at the end.
+ We repeat until all the identities are uptodate. */
+
+ do {
+ hit_count = 0;
+
+ for (ident = kcdb_identities;
+ ident != NULL;
+ ident = LNEXT(ident)) {
+
+ if (!kcdb_is_active_identity(ident) ||
+ ident->refresh_cycle == kcdb_ident_refresh_cycle)
+ continue;
+
+ kcdb_identity_hold((khm_handle) ident);
+
+ LeaveCriticalSection(&cs_ident);
+ kcdb_identity_refresh((khm_handle) ident);
+ EnterCriticalSection(&cs_ident);
+
+ kcdb_identity_release((khm_handle) ident);
+
+ hit_count++;
+ }
+ } while (hit_count > 0);
+
+ LeaveCriticalSection(&cs_ident);
+
+ return code;
+}
+
+/*****************************************/
+/* Custom property functions */
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_attr(khm_handle vid,
+ khm_int32 attr_id,
+ void * buffer,
+ khm_size cbbuf)
+{
+ kcdb_identity * id;
+ kcdb_attrib * attrib;
+ kcdb_type * type;
+ khm_size slot;
+ khm_size cbdest;
+ khm_int32 code = KHM_ERROR_SUCCESS;
+
+ EnterCriticalSection(&cs_ident);
+ if(!kcdb_is_active_identity(vid)) {
+ LeaveCriticalSection(&cs_ident);
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ id = (kcdb_identity *) vid;
+
+ if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS)) {
+ kcdb_buf_new(&id->buf, KCDB_BUF_DEFAULT);
+ id->flags |= KCDB_IDENT_FLAG_ATTRIBS;
+ }
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {
+ LeaveCriticalSection(&cs_ident);
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+#if 0
+ /* actually, even if an attribute is computed, we still allow
+ those values to be set. This is because computing values
+ is only for credentials. If a computed value is used as a
+ property in any other object, it is treated as a regular value
+ */
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)
+ {
+ LeaveCriticalSection(&cs_ident);
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_INVALID_OPERATION;
+ }
+#endif
+
+ if (buffer == NULL) {
+ /* we are removing a value */
+ slot = kcdb_buf_slot_by_id(&id->buf, attr_id);
+ if (slot != KCDB_BUF_INVALID_SLOT &&
+ kcdb_buf_exist(&id->buf, slot))
+ kcdb_buf_alloc(&id->buf, slot, attr_id, 0);
+ code = KHM_ERROR_SUCCESS;
+ goto _exit;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {
+ LeaveCriticalSection(&cs_ident);
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(!(type->isValid(buffer,cbbuf))) {
+ code = KHM_ERROR_TYPE_MISMATCH;
+ goto _exit;
+ }
+
+ if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ kcdb_buf_alloc(&id->buf, KCDB_BUF_APPEND, attr_id, cbdest);
+ slot = kcdb_buf_slot_by_id(&id->buf, attr_id);
+ if(slot == KCDB_BUF_INVALID_SLOT || !kcdb_buf_exist(&id->buf, slot)) {
+ code = KHM_ERROR_NO_RESOURCES;
+ goto _exit;
+ }
+
+ if(KHM_FAILED(code =
+ type->dup(buffer, cbbuf, kcdb_buf_get(&id->buf, slot), &cbdest)))
+ {
+ kcdb_buf_alloc(&id->buf, slot, attr_id, 0);
+ goto _exit;
+ }
+
+ kcdb_buf_set_value_flag(&id->buf, slot);
+
+_exit:
+ LeaveCriticalSection(&cs_ident);
+
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+ if(type)
+ kcdb_type_release_info(type);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_attrib(
+ khm_handle vid,
+ wchar_t * attr_name,
+ void * buffer,
+ khm_size cbbuf)
+{
+ khm_int32 attr_id = -1;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id)))
+ return KHM_ERROR_INVALID_PARM;
+
+ return kcdb_identity_set_attr(
+ vid,
+ attr_id,
+ buffer,
+ cbbuf);
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attr(
+ khm_handle vid,
+ khm_int32 attr_id,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcbbuf)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_identity * id = NULL;
+ kcdb_attrib * attrib = NULL;
+ kcdb_type * type = NULL;
+ khm_size slot;
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_UNKNOWN;
+ }
+
+ if(attr_type)
+ *attr_type = attrib->type;
+
+ EnterCriticalSection(&cs_ident);
+
+ if(!kcdb_is_active_identity(vid)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ id = (kcdb_identity *) vid;
+
+ if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) ||
+ (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT ||
+ !kcdb_buf_val_exist(&id->buf, slot))
+ {
+ code = KHM_ERROR_NOT_FOUND;
+ goto _exit;
+ }
+
+ if(!buffer && !pcbbuf) {
+ /* in this case the caller is only trying to determine if the field
+ contains data. If we get here, then the value exists. */
+ code = KHM_ERROR_SUCCESS;
+ goto _exit;
+ }
+
+#if 0
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {
+ /* we should never hit this case */
+#ifdef DEBUG
+ assert(FALSE);
+#else
+ code = KHM_ERROR_INVALID_OPERATION;
+#endif
+ } else {
+#endif
+ code = type->dup(
+ kcdb_buf_get(&id->buf, slot),
+ kcdb_buf_size(&id->buf, slot),
+ buffer,
+ pcbbuf);
+#if 0
+ }
+#endif
+
+_exit:
+ LeaveCriticalSection(&cs_ident);
+ if(type)
+ kcdb_type_release_info(type);
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attrib(
+ khm_handle vid,
+ wchar_t * attr_name,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcbbuf)
+{
+ khm_int32 attr_id = -1;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id)))
+ return KHM_ERROR_NOT_FOUND;
+
+ return kcdb_identity_get_attr(
+ vid,
+ attr_id,
+ attr_type,
+ buffer,
+ pcbbuf);
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attr_string(
+ khm_handle vid,
+ khm_int32 attr_id,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags)
+{
+ khm_int32 code = KHM_ERROR_SUCCESS;
+ kcdb_identity * id = NULL;
+ kcdb_attrib * attrib = NULL;
+ kcdb_type * type = NULL;
+ khm_size slot;
+
+ if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) {
+ kcdb_attrib_release_info(attrib);
+ return KHM_ERROR_UNKNOWN;
+ }
+
+ EnterCriticalSection(&cs_ident);
+
+ if(!kcdb_is_active_identity(vid)) {
+ code = KHM_ERROR_INVALID_PARM;
+ goto _exit;
+ }
+
+ id = (kcdb_identity *) vid;
+
+ if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) ||
+ (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT ||
+ !kcdb_buf_val_exist(&id->buf, slot))
+ {
+ code = KHM_ERROR_NOT_FOUND;
+ goto _exit;
+ }
+
+ if(!buffer && !pcbbuf) {
+ /* in this case the caller is only trying to determine if the field
+ contains data. If we get here, then the value exists */
+ code = KHM_ERROR_SUCCESS;
+ goto _exit;
+ }
+
+#if 0
+ if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) {
+#ifdef DEBUG
+ assert(FALSE);
+#else
+ code = KHM_ERROR_INVALID_OPERATION;
+#endif
+ } else {
+#endif
+ if(kcdb_buf_exist(&id->buf, slot)) {
+ code = type->toString(
+ kcdb_buf_get(&id->buf, slot),
+ kcdb_buf_size(&id->buf, slot),
+ buffer,
+ pcbbuf,
+ flags);
+ } else
+ code = KHM_ERROR_NOT_FOUND;
+#if 0
+ }
+#endif
+
+_exit:
+ LeaveCriticalSection(&cs_ident);
+ if(type)
+ kcdb_type_release_info(type);
+ if(attrib)
+ kcdb_attrib_release_info(attrib);
+
+ return code;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attrib_string(
+ khm_handle vid,
+ wchar_t * attr_name,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags)
+{
+ khm_int32 attr_id = -1;
+
+ if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id)))
+ return KHM_ERROR_NOT_FOUND;
+
+ return kcdb_identity_get_attr_string(
+ vid,
+ attr_id,
+ buffer,
+ pcbbuf,
+ flags);
+}
+
+/*****************************************/
+/* Identity provider interface functions */
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_validate_name(const wchar_t * name)
+{
+ kcdb_ident_name_xfer namex;
+ khm_handle sub;
+ khm_size cch;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ /* we need to verify the length and the contents of the string
+ before calling the identity provider */
+ if(FAILED(StringCchLength(name, KCDB_IDENT_MAXCCH_NAME, &cch)))
+ return KHM_ERROR_TOO_LONG;
+ if(wcsspn(name, KCDB_IDENT_VALID_CHARS) != cch)
+ return KHM_ERROR_INVALID_NAME;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ ZeroMemory(&namex, sizeof(namex));
+
+ namex.name_src = name;
+ namex.result = KHM_ERROR_NOT_IMPLEMENTED;
+
+ kmq_send_sub_msg(sub,
+ KMSG_IDENT,
+ KMSG_IDENT_VALIDATE_NAME,
+ 0,
+ (void *) &namex);
+
+ rv = namex.result;
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_validate_identity(khm_handle identity)
+{
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ khm_handle sub;
+
+ if(!kcdb_is_active_identity(identity))
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ rv = kmq_send_sub_msg(sub,
+ KMSG_IDENT,
+ KMSG_IDENT_VALIDATE_IDENTITY,
+ 0,
+ (void *) identity);
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_canon_name(
+ const wchar_t * name_in,
+ wchar_t * name_out,
+ khm_size * cb_name_out)
+{
+ khm_handle sub;
+ kcdb_ident_name_xfer namex;
+ wchar_t name_tmp[KCDB_IDENT_MAXCCH_NAME];
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ khm_size cch;
+
+ if(cb_name_out == 0 ||
+ FAILED(StringCchLength(name_in, KCDB_IDENT_MAXCCH_NAME, &cch)) ||
+ wcsspn(name_in, KCDB_IDENT_VALID_CHARS) != cch)
+ return KHM_ERROR_INVALID_NAME;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ ZeroMemory(&namex, sizeof(namex));
+ ZeroMemory(name_tmp, sizeof(name_tmp));
+
+ namex.name_src = name_in;
+ namex.name_dest = name_tmp;
+ namex.cb_name_dest = sizeof(name_tmp);
+ namex.result = KHM_ERROR_NOT_IMPLEMENTED;
+
+ rv = kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_CANON_NAME,
+ 0,
+ (void *) &namex);
+
+ if(KHM_SUCCEEDED(namex.result)) {
+ const wchar_t * name_result;
+ khm_size cb;
+
+ if(name_in[0] != 0 && name_tmp[0] == 0)
+ name_result = name_tmp;
+ else
+ name_result = name_in;
+
+ if(FAILED(StringCbLength(name_result, KCDB_IDENT_MAXCB_NAME, &cb)))
+ rv = KHM_ERROR_UNKNOWN;
+ else {
+ cb += sizeof(wchar_t);
+ if(name_out == 0 || *cb_name_out < cb) {
+ rv = KHM_ERROR_TOO_LONG;
+ *cb_name_out = cb;
+ } else {
+ StringCbCopy(name_out, *cb_name_out, name_result);
+ *cb_name_out = cb;
+ rv = KHM_ERROR_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_compare_name(
+ const wchar_t * name1,
+ const wchar_t * name2)
+{
+ khm_handle sub;
+ kcdb_ident_name_xfer namex;
+ khm_int32 rv = 0;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ /* Generally in kcdb_identpro_* functions we don't emulate
+ any behavior if the provider is not available, but lacking
+ a way to make this known, we emulate here */
+ rv = wcscmp(name1, name2);
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ ZeroMemory(&namex, sizeof(namex));
+ namex.name_src = name1;
+ namex.name_alt = name2;
+
+ kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_COMPARE_NAME,
+ 0,
+ (void *) &namex);
+
+ rv = namex.result;
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_set_default(
+ khm_handle identity)
+{
+ khm_handle sub;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if((identity != NULL) &&
+ !kcdb_is_active_identity(identity))
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ rv = kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_SET_DEFAULT,
+ (identity != NULL),
+ (void *) identity);
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_set_searchable(
+ khm_handle identity,
+ khm_boolean searchable)
+{
+ khm_handle sub;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!kcdb_is_active_identity(identity))
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ rv = kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_SET_SEARCHABLE,
+ searchable,
+ (void *) identity);
+ }
+
+ return rv;
+}
+
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_update(khm_handle identity)
+{
+ khm_handle sub;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!kcdb_is_active_identity(identity))
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ rv = kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_UPDATE,
+ 0,
+ (void *) identity);
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_notify_create(khm_handle identity)
+{
+ khm_handle sub;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(!kcdb_is_active_identity(identity))
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ rv = kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_NOTIFY_CREATE,
+ 0,
+ (void *) identity);
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_identpro_get_ui_cb(void * rock)
+{
+ khm_handle sub;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ EnterCriticalSection(&cs_ident);
+ if(kcdb_ident_sub != NULL) {
+ sub = kcdb_ident_sub;
+ } else {
+ sub = NULL;
+ rv = KHM_ERROR_NO_PROVIDER;
+ }
+ LeaveCriticalSection(&cs_ident);
+
+ if(sub != NULL) {
+ rv = kmq_send_sub_msg(
+ sub,
+ KMSG_IDENT,
+ KMSG_IDENT_GET_UI_CALLBACK,
+ 0,
+ rock);
+ }
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_identity_enum(
+ khm_int32 and_flags,
+ khm_int32 eq_flags,
+ wchar_t * name_buf,
+ khm_size * pcb_buf,
+ khm_size * pn_idents)
+{
+ kcdb_identity * id;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ khm_size cb_req = 0;
+ khm_size n_idents = 0;
+ size_t cb_curr;
+ size_t cch_curr;
+ size_t cch_left;
+ HRESULT hr;
+
+ if ((name_buf == NULL && pcb_buf == NULL && pn_idents == NULL) ||
+ (name_buf != NULL && pcb_buf == NULL))
+ return KHM_ERROR_INVALID_PARM;
+
+ eq_flags &= and_flags;
+
+ EnterCriticalSection(&cs_ident);
+
+ if (!kcdb_checked_config) {
+ khm_handle h_kcdb = NULL;
+ khm_handle h_idents = NULL;
+ khm_handle h_ident = NULL;
+
+ h_kcdb = kcdb_get_config();
+ if (!h_kcdb)
+ goto _config_check_cleanup;
+ if(KHM_FAILED(khc_open_space(h_kcdb, L"Identity", 0, &h_idents)))
+ goto _config_check_cleanup;
+
+ while(KHM_SUCCEEDED(khc_enum_subspaces(h_idents,
+ h_ident,
+ &h_ident))) {
+
+ wchar_t wname[KCDB_IDENT_MAXCCH_NAME];
+ khm_size cb;
+ khm_handle t_id;
+
+ cb = sizeof(wname);
+ if (KHM_FAILED(khc_get_config_space_name(h_ident,
+ wname,
+ &cb)))
+ continue;
+
+ if (KHM_SUCCEEDED(kcdb_identity_create(wname,
+ KCDB_IDENT_FLAG_CREATE,
+ &t_id)))
+ kcdb_identity_release(t_id);
+ }
+
+ _config_check_cleanup:
+ if (h_kcdb)
+ khc_close_space(h_kcdb);
+ if (h_idents)
+ khc_close_space(h_idents);
+
+ kcdb_checked_config = TRUE;
+ }
+
+ for ( id = kcdb_identities;
+ id != NULL;
+ id = LNEXT(id) ) {
+ if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) ==
+ KCDB_IDENT_FLAG_ACTIVE) &&
+ ((id->flags & and_flags) == eq_flags)) {
+ n_idents ++;
+ hr = StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &cb_curr);
+#ifdef DEBUG
+ assert(SUCCEEDED(hr));
+#endif
+ cb_req += cb_curr + sizeof(wchar_t);
+ }
+ }
+
+ cb_req += sizeof(wchar_t);
+
+ if (pn_idents != NULL)
+ *pn_idents = n_idents;
+
+ if (pcb_buf != NULL && (name_buf == NULL || *pcb_buf < cb_req)) {
+ *pcb_buf = cb_req;
+
+ rv = KHM_ERROR_TOO_LONG;
+ } else if(name_buf != NULL) {
+ cch_left = (*pcb_buf) / sizeof(wchar_t);
+
+ for (id = kcdb_identities;
+ id != NULL;
+ id = LNEXT(id)) {
+ if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) ==
+ KCDB_IDENT_FLAG_ACTIVE) &&
+ ((id->flags & and_flags) == eq_flags)) {
+ StringCchLength(id->name, KCDB_IDENT_MAXCCH_NAME,
+ &cch_curr);
+ cch_curr++;
+ StringCchCopy(name_buf, cch_left, id->name);
+ cch_left -= cch_curr;
+ name_buf += cch_curr;
+ }
+ }
+
+ *name_buf = L'\0';
+ *pcb_buf = cb_req;
+ }
+
+ LeaveCriticalSection(&cs_ident);
+
+ return rv;
+}
diff --git a/src/windows/identity/kcreddb/identity.h b/src/windows/identity/kcreddb/identity.h
new file mode 100644
index 0000000..6c7e26e
--- /dev/null
+++ b/src/windows/identity/kcreddb/identity.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_IDENTITY_H
+#define __KHIMAIRA_KCDB_IDENTITY_H
+
+/* Identity */
+
+#define KCDB_IDENT_HASHTABLE_SIZE 31
+
+typedef struct kcdb_identity_t {
+ khm_int32 magic;
+ wchar_t * name;
+ khm_int32 flags;
+ khm_int32 refcount;
+ kcdb_buf buf;
+ khm_ui_4 refresh_cycle;
+ struct kcdb_identity_t * next;
+ struct kcdb_identity_t * prev;
+} kcdb_identity;
+
+#define KCDB_IDENT_MAGIC 0x31938d4f
+
+extern CRITICAL_SECTION cs_ident;
+extern hashtable * kcdb_identities_namemap;
+extern khm_int32 kcdb_n_identities;
+extern kcdb_identity * kcdb_identities; /* all identities */
+extern kcdb_identity * kcdb_def_identity; /* default identity */
+extern khm_ui_4 kcdb_ident_refresh_cycle;
+
+void kcdbint_ident_init(void);
+void kcdbint_ident_exit(void);
+void kcdbint_ident_msg_completion(kmq_message * m);
+void kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id);
+
+#define kcdb_is_identity(id) ((id) && ((kcdb_identity *)(id))->magic == KCDB_IDENT_MAGIC)
+#define kcdb_is_active_identity(id) (kcdb_is_identity(id) && (((kcdb_identity *)(id))->flags & KCDB_IDENT_FLAG_ACTIVE))
+
+#endif
diff --git a/src/windows/identity/kcreddb/init.c b/src/windows/identity/kcreddb/init.c
new file mode 100644
index 0000000..2df3f3e
--- /dev/null
+++ b/src/windows/identity/kcreddb/init.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+
+/* set to TRUE when the configuration is loaded */
+static int kcdb_config_loaded = 0;
+
+/* global state cs */
+static CRITICAL_SECTION cs_kcdb_global;
+
+/* forward dcl */
+void KHMAPI kcdb_msg_completion(kmq_message * m);
+
+void kcdb_init(void) {
+ /* setup the critical sections */
+ InitializeCriticalSection(&cs_kcdb_global);
+
+ kmq_set_completion_handler(KMSG_KCDB, kcdb_msg_completion);
+
+ kcdb_credtype_init();
+ kcdbint_ident_init();
+ kcdb_credset_init();
+ kcdb_cred_init();
+ kcdb_type_init();
+ kcdb_attrib_init();
+}
+
+void kcdb_exit(void) {
+
+ kcdb_attrib_exit();
+ kcdb_type_exit();
+ kcdb_cred_exit();
+ kcdb_credset_exit();
+ kcdbint_ident_exit();
+ kcdb_credtype_exit();
+
+ kmq_set_completion_handler(KMSG_KCDB, NULL);
+
+ DeleteCriticalSection(&cs_kcdb_global);
+}
+
+khm_handle kcdb_get_config(void) {
+ khm_handle space = NULL;
+
+ EnterCriticalSection(&cs_kcdb_global);
+ if(!kcdb_config_loaded) {
+ khc_load_schema(NULL, schema_kcdbconfig);
+ kcdb_config_loaded = 1;
+ }
+ khc_open_space(NULL, L"KCDB", 0, &space);
+ LeaveCriticalSection(&cs_kcdb_global);
+
+ return space;
+}
+
+void KHMAPI kcdb_msg_completion(kmq_message * m) {
+ if(!m)
+ return;
+ if(m->subtype == KMSG_KCDB_IDENT)
+ kcdbint_ident_msg_completion(m);
+ else if(m->subtype == KMSG_KCDB_ATTRIB)
+ kcdb_attrib_msg_completion(m);
+ else if(m->subtype == KMSG_KCDB_TYPE)
+ kcdb_type_msg_completion(m);
+ else if(m->subtype == KMSG_KCDB_CREDTYPE)
+ kcdb_credtype_msg_completion(m);
+}
diff --git a/src/windows/identity/kcreddb/kcdbconfig.csv b/src/windows/identity/kcreddb/kcdbconfig.csv
new file mode 100644
index 0000000..bd1fc6f
--- /dev/null
+++ b/src/windows/identity/kcreddb/kcdbconfig.csv
@@ -0,0 +1,15 @@
+Name,Type,Value,Description
+KCDB,KC_SPACE,0,Khimaira Configuration DB
+ Identity,KC_SPACE,0,Configuration space for identities
+ _Schema,KC_SPACE,0,Schema for identities
+ Sticky,KC_INT32,0,Boolean. Is this a sticky identity?
+ Monitor,KC_INT32,1,Boolean. Enables monitoring the identity
+ WarnThreshold,KC_INT32,900,In seconds
+ AllowWarn,KC_INT32,1,Boolean. Allow warning.
+ CriticalThreshold,KC_INT32,60,In seconds
+ AllowCritical,KC_INT32,1,Boolean. Allow critical.
+ AutoRenewThreshold,KC_INT32,60,In seconds
+ AllowAutoRenew,KC_INT32,1,Boolean.
+ _Schema,KC_ENDSPACE,0,
+ Identity,KC_ENDSPACE,0,
+KCDB,KC_ENDSPACE,0,
diff --git a/src/windows/identity/kcreddb/kcreddb.h b/src/windows/identity/kcreddb/kcreddb.h
new file mode 100644
index 0000000..e5be0f4
--- /dev/null
+++ b/src/windows/identity/kcreddb/kcreddb.h
@@ -0,0 +1,3212 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCREDDB_H__
+#define __KHIMAIRA_KCREDDB_H__
+
+#include<khdefs.h>
+#include<time.h>
+
+
+/*! \defgroup kcdb NetIDMgr Credentials Database */
+/*@{*/
+
+/*! \brief Maximum length in characters of short description
+
+ The length includes the terminating \a NULL character.
+ */
+#define KCDB_MAXCCH_SHORT_DESC 256
+
+/*! \brief Maximum length in bytes of short description
+
+ The length includes the terminating \a NULL character.
+ */
+#define KCDB_MAXCB_SHORT_DESC (sizeof(wchar_t) * KCDB_MAXCCH_SHORT_DESC)
+
+/*! \brief Maximum length in characters of long description
+
+ The length includes the terminating \a NULL character.
+ */
+#define KCDB_MAXCCH_LONG_DESC 8192
+
+/*! \brief Maximum length in characters of long description
+
+ The length includes the terminating \a NULL character.
+ */
+#define KCDB_MAXCB_LONG_DESC (sizeof(wchar_t) * KCDB_MAXCCH_LONG_DESC)
+
+/*! \brief Maximum length in characters of name
+
+ The length includes the terminating \a NULL character.
+ */
+#define KCDB_MAXCCH_NAME 256
+
+/*! \brief Maximum length in bytes of short description
+
+ The length includes the terminating \a NULL character.
+ */
+#define KCDB_MAXCB_NAME (sizeof(wchar_t) * KCDB_MAXCCH_NAME)
+
+/*! \brief Automatically determine the number of bytes required
+
+ Can be used in most places where a count of bytes is required.
+ For many objects, the number of bytes that are required can be
+ determined through context and may be ommited. In such cases you
+ can use the \a KCDB_CBSIZE_AUTO value to specify that the function
+ is to determine the size automatically.
+
+ \note Not all functions that take a count of bytes support the \a
+ KCDB_CBSIZE_AUTO value.
+*/
+#define KCDB_CBSIZE_AUTO (-1)
+
+/*!
+\defgroup kcdb_ident Identities
+
+Functions, macros etc. for manipulating identities.
+*/
+
+/*@{*/
+
+/*! \brief The maximum number of characters (including terminator) that can
+ be specified as an identity name */
+#define KCDB_IDENT_MAXCCH_NAME 256
+
+/*! \brief The maximum number of bytes that can be specified as an identity
+ name */
+#define KCDB_IDENT_MAXCB_NAME (sizeof(wchar_t) * KCDB_IDENT_MAXCCH_NAME)
+
+/*! \brief Valid characters in an identity name */
+#define KCDB_IDENT_VALID_CHARS L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._@-/"
+
+/*!
+\name Flags for identities */
+/*@{*/
+
+/*! \brief Create the identity if it doesn't already exist.
+ \note Only to be used with kcdb_identity_create() */
+#define KCDB_IDENT_FLAG_CREATE 0x10000000L
+
+/*! \brief Inverts the accompanying flags.
+
+ \note Only to be used with kcdb_identity_set_flags()
+ \see kcdb_identity_set_flags() */
+#define KCDB_IDENT_FLAG_INVERT 0x40000000L
+
+/*! \brief Has configuration information
+
+ Indicates that the identity has persistent configuration
+ information associated with it.
+ */
+#define KCDB_IDENT_FLAG_CONFIG 0x00800000L
+
+/*! \brief Marks the identity as active.
+
+ An active identity is one that is in active use within NetIDMgr.
+
+ \note This flag is readonly and cannot be specified when creating
+ or modifying an identity. Once an identity is deleted, it will
+ no longer have this flag. */
+#define KCDB_IDENT_FLAG_ACTIVE 0x02000000L
+
+/*! \brief Sticky identity
+
+ Sticky identities are identities that are always visible in the
+ credentials display even if no credentials are associated with it.
+ */
+#define KCDB_IDENT_FLAG_STICKY 0x04000000L
+
+/*! \brief The identity has custom attributes assigned
+ */
+#define KCDB_IDENT_FLAG_ATTRIBS 0x08000000L
+
+/*! \brief This is the default identity.
+
+ At most one identity will have this flag set at any given time.
+ To set or reset the flag, use kcdb_identity_set_default() */
+#define KCDB_IDENT_FLAG_DEFAULT 0x00000001L
+
+/*! \brief This identity can be searched.
+
+ The meaning of this flag is left to be interpreted by individual
+ plugins. */
+#define KCDB_IDENT_FLAG_SEARCHABLE 0x00000002L
+
+/*! \brief Hidden identity.
+
+ The identity will not show up in the identity list window. Once
+ the hidden is switched off, the identity (and all associated
+ credentials) will re-appear in the window */
+#define KCDB_IDENT_FLAG_HIDDEN 0x00000004L
+
+/*! \brief Invalid identity
+
+ For one reason or another, this identity is invalid. This flag
+ can be set by an identity provider to indicate that this identity
+ does not correspond to an actual identity because an external
+ entity (such as a KDC) has denied it's existence.
+
+ The absence of this flag does not imply that the identity is
+ valid. The ::KCDB_IDENT_FLAG_VALID bit must be set for that to be
+ the case. If neither flag is set, then the status of the identity
+ is not known.
+*/
+#define KCDB_IDENT_FLAG_INVALID 0x00000008L
+
+/*! \brief Valid identity
+
+ The identity has been validated through an external entity, or
+ it's validity implied through the existence of credentials for the
+ identity.
+
+ The absence of this flag does not imply that the identity is
+ invalid. The ::KCDB_IDENT_FLAG_INVALID bit must be set for that
+ to be the case. If neither flag is set, then the status of the
+ identity is not known.
+ */
+#define KCDB_IDENT_FLAG_VALID 0x00000010L
+
+/*! \brief Expired identity
+
+ This identity has expired and can not be actively used to obtain
+ credentials. This determination is made based on the input of
+ some external entity. This flag may only be set by an identity
+ provider.
+*/
+#define KCDB_IDENT_FLAG_EXPIRED 0x00000020L
+
+/*! \brief Empty identity
+
+ The identity does not have actual credentials associated with it.
+ */
+#define KCDB_IDENT_FLAG_EMPTY 0x00000040L
+
+/*! \brief Renewable identity
+
+ The initial credentials associated with this identity are
+ renewable. Thus making the whole identity renewable.
+ */
+#define KCDB_IDENT_FLAG_RENEWABLE 0x00000080L
+
+/*! \brief Required user interaction
+
+ The identity is in a state which requires user interaction to
+ activate. Currently, the identity may not be in a state where it
+ can be used to obtain credentials.
+
+ A typical example of this is when the primary password for an
+ identity has expired.
+ */
+#define KCDB_IDENT_FLAG_INTERACT 0x00000100L
+
+/*! \brief Has expired credentials
+
+ The identity has expired credentials associated with it.
+ */
+#define KCDB_IDENT_FLAG_CRED_EXP 0x00000200L
+
+/*! \brief Has renewable credentials
+
+ The identity has renewable credentials associated with it. If the
+ initial credentials of the identity are renewable, then identity
+ is renewable. Hence the ::KCDB_IDENT_FLAG_RENEWABLE should also
+ be set.
+ */
+#define KCDB_IDENT_FLAG_CRED_RENEW 0x00000400L
+
+/*! \brief Bit mask for local flags
+
+ Local flags are those local to the KCDB.
+ */
+#define KCDB_IDENT_FLAGMASK_LOCAL 0x0000ffffL
+
+/*! \brief Read/write flags mask.
+
+ A bitmask that correspond to all the read/write flags in the mask.
+*/
+#define KCDB_IDENT_FLAGMASK_RDWR 0x000007ffL
+
+/*@}*/
+
+/*! \name Identity Provider Data Structures
+@{*/
+
+/*! \brief Name transfer structure
+
+ Used when the KCDB is communicating with the identity provider to
+ exchange string names of identities. See individual ::KMSG_IDENT
+ message subtypes for the usage of this structure.
+ */
+typedef struct tag_kcdb_ident_name_xfer {
+ const wchar_t * name_src; /*!< An identity name. Does not
+ exceed KCDB_IDENT_MAXCCH_NAME
+ characters including terminating
+ NULL. */
+ const wchar_t * name_alt; /*!< An identity name. Does not
+ exceed KCDB_IDENT_MAXCCH_NAME
+ characters including terminating
+ NULL. */
+ wchar_t * name_dest; /*!< Pointer to a buffer that is to
+ receive a response string. The
+ size of the buffer in bytes is
+ specified in \a cb_name_dest. */
+ khm_size cb_name_dest; /*!< Size of buffer pointed to by \a
+ name_dest in bytes. */
+ khm_int32 result; /*!< Receives a result value, which is
+ usually an error code defined in
+ kherror.h, though it is not
+ always. */
+} kcdb_ident_name_xfer;
+
+typedef struct tag_kcdb_ident_info {
+ khm_handle identity;
+ khm_int32 fields;
+
+ FILETIME expiration;
+} kcdb_ident_info;
+
+/*@}*/
+
+/*! \name Identity provider interface functions
+
+ These functions encapsulate safe calls to the current identity
+ provider. While these functions are exported, applications should
+ not call these functions directly. They are provided for use by
+ the NetIDMgr core application.
+@{*/
+
+/*! \brief Validate an identity name
+
+ The name that is provided will be passed through sets of
+ validations. One set, which doesn't depend on the identity
+ provider checks whether the length of the identity name and
+ whether there are any invalid characters in the identity name. If
+ the name passes those tests, then the name is passed down to the
+ identity provider's name validation handler.
+
+ \retval KHM_ERROR_SUCCESS The name is valid
+ \retval KHM_ERROR_TOO_LONG Too many characters in name
+ \retval KHM_ERROR_INVALID_NAME There were invalid characters in the name.
+ \retval KHM_ERROR_NO_PROVIDER There is no identity provider;
+ however the name passed the length and character tests.
+ \retval KHM_ERROR_NOT_IMPLEMENTED The identity provider doesn't
+ implement a name validation handler; however the name passed
+ the length and character tests.
+
+ \see ::KMSG_IDENT_VALIDATE_NAME
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_validate_name(const wchar_t * name);
+
+/*! \brief Validate an identity
+
+ The identity itself needs to be validated. This may involve
+ communicating with an external entity.
+
+ \see ::KMSG_IDENT_VALIDATE_IDENTITY
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_validate_identity(khm_handle identity);
+
+/*! \brief Canonicalize the name
+
+
+ \see ::KMSG_IDENT_CANON_NAME
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_canon_name(const wchar_t * name_in,
+ wchar_t * name_out,
+ khm_size * cb_name_out);
+
+/*! \brief Compare two identity names
+
+ \see ::KMSG_IDENT_COMPARE_NAME
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_compare_name(const wchar_t * name1,
+ const wchar_t * name2);
+
+/*! \brief Set the specified identity as the default
+
+ \see ::KMSG_IDENT_SET_DEFAULT
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_set_default(khm_handle identity);
+
+/*! \brief Set the specified identity as searchable
+
+ \see ::KMSG_IDENT_SET_SEARCHABLE
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_set_searchable(khm_handle identity,
+ khm_boolean searchable);
+
+/*! \brief Update the specified identity
+
+ \see ::KMSG_IDENT_UPDATE
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_update(khm_handle identity);
+
+/*! \brief Obtain the UI callback
+
+ \a rock is actually a pointer to a ::khui_ident_new_creds_cb which
+ is to receive the callback.
+
+ \see ::KMSG_IDENT_GET_UI_CALLBACK
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_get_ui_cb(void * rock);
+
+/*! \brief Notify an identity provider of the creation of a new identity
+
+ \see ::KMSG_IDENT_NOTIFY_CREATE
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identpro_notify_create(khm_handle identity);
+
+/*@}*/
+
+/*! \brief Check if the given name is a valid identity name
+
+ \return TRUE or FALSE to the question, is this valid?
+*/
+KHMEXP khm_boolean KHMAPI
+kcdb_identity_is_valid_name(const wchar_t * name);
+
+/*! \brief Create or open an identity.
+
+ If the KCDB_IDENT_FLAG_CREATE flag is specified in the flags
+ parameter a new identity will be created if one does not already
+ exist with the given name. If an identity by that name already
+ exists, then the existing identity will be opened. The result
+ parameter will receive a held reference to the opened identity.
+ Use kcdb_identity_release() to release the handle.
+
+ \param[in] name Name of identity to create
+ \param[in] flags If KCDB_IDENT_FLAG_CREATE is specified, then the
+ identity will be created if it doesn't already exist.
+ Additional flags can be set here which will be assigned to the
+ identity if it is created. Additional flags have no effect if
+ an existing identity is opened.
+ \param[out] result If the call is successful, this receives a held
+ reference to the identity. The caller should call
+ kcdb_identity_release() to release the identity once it is no
+ longer needed.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_create(const wchar_t *name,
+ khm_int32 flags,
+ khm_handle * result);
+
+/*! \brief Mark an identity for deletion.
+
+ The identity will be marked for deletion. The
+ KCDB_IDENT_FLAG_ACTIVE will no longer be present for this
+ identity. Once all references to the identity are released, it
+ will be removed from memory. All associated credentials will also
+ be removed. */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_delete(khm_handle id);
+
+/*! \brief Set or unset the specified flags in the specified identity.
+
+ Only flags that are in KCDB_IDENT_FLAGMASK_RDWR can be specifed
+ in the flags parameter. The only exception is the
+ KCDB_IDENT_FLAG_INVERT flag which controls whether the flags are
+ to be set or reset.
+
+ If the ::KCDB_IDENT_FLAG_INVERT flag is not specified in \a flags,
+ then any flags set in \a flags will also be set in the identity.
+ If the ::KCDB_IDENT_FLAG_INVERT is specified, then any flag set in
+ \a flags will be reset in the identity.
+
+ If ::KCDB_IDENT_FLAG_INVALID is set using this function, then the
+ ::KCDB_IDENT_FLAG_VALID will be automatically reset, and vice
+ versa. Resetting either bit does not undo this change, and will
+ leave the identity's validity unspecified.
+
+ Note that setting or resetting certain flags have other semantic
+ side-effects:
+
+ - ::KCDB_IDENT_FLAG_DEFAULT : Setting this is equivalent to
+ calling kcdb_identity_set_default() with \a id. Resetting this
+ is equivalent to calling kcdb_identity_set_default() with NULL.
+
+ - ::KCDB_IDENT_FLAG_SEARCHABLE : Setting this will result in the
+ identity provider getting notified of the change. If the
+ identity provider indicates that searchable flag should not be
+ set or reset (according to KCDB_IDENT_FLAG_INVERT setting) on
+ the identity, then kcdb_identity_set_flags() will return an
+ error.
+
+ \note kcdb_identity_set_flags() is not atomic. Even if the
+ function returns a failure code, some flags in the identity may
+ have been set. When calling kcdb_identity_set_flags() always
+ check the flags in the identity using kcdb_identity_get_flags() to
+ check which flags have been set and which have failed.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_flags(khm_handle id,
+ khm_int32 flags);
+
+/*! \brief Return all the flags for the identity
+
+ The returned flags may include internal flags.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_flags(khm_handle id,
+ khm_int32 * flags);
+
+/*! \brief Return the name of the identity
+
+ \param[out] buffer Buffer to copy the identity name into. The
+ maximum size of an identity name is \a KCDB_IDENT_MAXCB_NAME.
+ If \a buffer is \a NULL, then the required size of the buffer
+ is returned in \a pcbsize.
+
+ \param[in,out] pcbsize Size of buffer in bytes. */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_name(khm_handle id,
+ wchar_t * buffer,
+ khm_size * pcbsize);
+
+/*! \brief Set the specified identity as the default.
+
+ Specifying NULL effectively makes none of the identities the
+ default.
+
+ \see kcdb_identity_set_flags()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_default(khm_handle id);
+
+/*! \brief Mark the specified identity as the default.
+
+ This API is reserved for use by identity providers as a means of
+ specifying which identity is default. The difference between
+ kcdb_identity_set_default() and kcdb_identity_set_default_int() is
+ in semantics.
+
+ - kcdb_identity_set_default() is used to request the KCDB to
+ designate the specified identity as the default. When
+ processing the request, the KCDB invokes the identity provider
+ to do the necessary work to make the identity the default.
+
+ - kcdb_identity_set_default_int() is used by the identity provider
+ to notify the KCDB that the specified identity is the default.
+ This does not result in the invocation of any other semantics to
+ make the identity the default other than releasing the previous
+ defualt identity and making the specified one the default. As
+ an additional side effect, the notification <::KMSG_KCDB,
+ ::KMSG_KCDB_IDENT, ::KCDB_OP_NEW_DEFAULT> will also not be sent.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_default_int(khm_handle id);
+
+/*! \brief Get the default identity
+
+ Obtain a held handle to the default identity if there is one. The
+ handle must be freed using kcdb_identity_release().
+
+ If there is no default identity, then the handle pointed to by \a
+ pvid is set to \a NULL and the function returns
+ KHM_ERROR_NOT_FOUND. */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_default(khm_handle * pvid);
+
+/*! \brief Get the configuration space for the identity.
+
+ \param[in] id Identity for which the configuraiton space is requested
+
+ \param[in] flags Flags used when calling khc_open_space(). If \a
+ flags specifies KHM_FLAG_CREATE, then the configuration space
+ is created.
+
+ \param[out] result The resulting handle. If the call is
+ successful, this receives a handle to the configuration space.
+ Use khc_close_space() to close the handle.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_config(khm_handle id,
+ khm_int32 flags,
+ khm_handle * result);
+
+/*! \brief Hold a reference to an identity.
+
+ A reference to an identity (a handle) is only valid while it is
+ held. \note Once the handle is released, it can not be
+ revalidated by calling kcdb_identity_hold(). Doing so would lead
+ to unpredictable consequences. */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_hold(khm_handle id);
+
+/*! \brief Release a reference to an identity.
+ \see kcdb_identity_hold() */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_release(khm_handle id);
+
+/*! \brief Set the identity provider subscription
+
+ If there was a previous subscription, that subscription will be
+ automatically deleted.
+
+ \param[in] sub New identity provider subscription
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_provider(khm_handle sub);
+
+/*! \brief Set the primary credentials type
+
+ The primary credentials type is designated by the identity
+ provider. As such, this function should only be called by an
+ identity provider.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_type(khm_int32 cred_type);
+
+/*! \brief Retrieve the identity provider subscription
+
+ \param[out] sub Receives the current identity provider
+ subscription. Set to NULL if only the existence of an
+ identity provider needs to be checked.
+
+ \retval KHM_ERROR_SUCCESS An identity provider exists. If \a sub
+ was not NULL, the subscription has been copied there.
+
+ \retval KHM_ERROR_NOT_FOUND There is currently no registered
+ identity provider. If \a sub was not NULL, the handle it
+ points to has been set to NULL.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_provider(khm_handle * sub);
+
+/*! \brief Retrieve the identity provider credentials type
+
+ This is the credentials type that the identity provider has
+ designated as the primary credentials type.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_type(khm_int32 * ptype);
+
+/*! \brief Set an attribute in an identity by attribute id
+
+ \param[in] buffer A pointer to a buffer containing the data to
+ assign to the attribute. Setting \a buffer to NULL has the
+ effect of removing any data that is already assigned to the
+ attribute. If \a buffer is non-NULL, then \a cbbuf should
+ specify the number of bytes in \a buffer.
+
+ \param[in] cbbuf Number of bytes of data in \a buffer. The
+ individual data type handlers may copy in less than this many
+ bytes in to the credential.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_attr(khm_handle identity,
+ khm_int32 attr_id,
+ void * buffer,
+ khm_size cbbuf);
+
+/*! \brief Set an attribute in an identity by name
+
+ The attribute name has to be a KCDB registered attribute or
+ property.
+
+ \param[in] cbbuf Number of bytes of data in \a buffer. The
+ individual data type handlers may copy in less than this many
+ bytes in to the credential.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_set_attrib(khm_handle identity,
+ wchar_t * attr_name,
+ void * buffer,
+ khm_size cbbuf);
+
+/*! \brief Get an attribute from an identity by attribute id.
+
+ \param[in] buffer The buffer that is to receive the attribute
+ value. Set this to NULL if only the required buffer size is
+ to be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+
+ \param[out] attr_type Receives the data type of the attribute.
+ Set this to NULL if the type is not required.
+
+ \note Set both \a buffer and \a cbbuf to NULL if only the
+ existence of the attribute is to be checked. If the attribute
+ exists in this identity then the function will return
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attr(khm_handle identity,
+ khm_int32 attr_id,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcbbuf);
+
+/*! \brief Get an attribute from an identity by name.
+
+ \param[in] buffer The buffer that is to receive the attribute
+ value. Set this to NULL if only the required buffer size is
+ to be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+
+ \note Set both \a buffer and \a cbbuf to NULL if only the
+ existence of the attribute is to be checked. If the attribute
+ exists in this identity then the function will return
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attrib(khm_handle identity,
+ wchar_t * attr_name,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcbbuf);
+
+/*! \brief Get the string representation of an identity attribute.
+
+ A shortcut function which generates the string representation of
+ an identity attribute directly.
+
+ \param[in] identity A handle to an identity
+
+ \param[in] attr_id The attribute to retrieve
+
+ \param[out] buffer A pointer to a string buffer which receives the
+ string form of the attribute. Set this to NULL if you only
+ want to determine the size of the required buffer.
+
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,
+ holds the size of the buffer pointed to by \a buffer, and on
+ exit, receives the actual number of bytes that were copied.
+
+ \param[in] flags Flags for the string conversion. Can be set to
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is
+ KCDB_TS_LONG.
+
+ \retval KHM_ERROR_SUCCESS Success
+ \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid
+ or was not defined for this identity
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid
+ \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the
+ supplied buffer was insufficient
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attr_string(khm_handle identity,
+ khm_int32 attr_id,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags);
+
+/*! \brief Get the string representation of an identity attribute by name.
+
+ A shortcut function which generates the string representation of
+ an identity attribute directly.
+
+ \param[in] identity A handle to an identity
+
+ \param[in] attrib The name of the attribute to retrieve
+
+ \param[out] buffer A pointer to a string buffer which receives the
+ string form of the attribute. Set this to NULL if you only
+ want to determine the size of the required buffer.
+
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,
+ holds the size of the buffer pointed to by \a buffer, and on
+ exit, receives the actual number of bytes that were copied.
+
+ \param[in] flags Flags for the string conversion. Can be set to
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is
+ KCDB_TS_LONG.
+
+ \see kcdb_identity_get_attr_string()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_get_attrib_string(khm_handle identity,
+ wchar_t * attr_name,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags);
+
+/*! \brief Enumerate identities
+
+ Enumerates all the active identities that match the criteria
+ specified using \a and_flags and \a eq_flags. The condition is
+ applied to all active identities as follows:
+
+ \code
+ (identity->flags & and_flags) == (eq_flags & and_flags)
+ \endcode
+
+ Essentially, if a flag is set in \a and_flags, then that flag in
+ the identity should equal the setting in \a eq_flags.
+
+ \param[in] and_flags See above
+
+ \param[in] eq_flags See above
+
+ \param[out] name_buf Buffer to receive the list of identity names.
+ Can be NULL if only the required size of the buffer or the
+ number of matching identities is required. The list is
+ returned as a multi string.
+
+ \param[in,out] pcb_buf Number of bytes in buffer pointed to by \a
+ name_buf on entry. On exit, will receive the number of bytes
+ copied. Can be NULL only if \a name_buf is also NULL. If \a
+ name_buf is NULL or if \a pcb_buf indicates that the buffer is
+ insufficient, this will receive the number of bytes required
+ and the return value of the function will be
+ KHM_ERROR_TOO_LONG
+
+ \param[out] pn_idents Receives the number of identities that match
+ the given criteria.
+
+ \retval KHM_ERROR_SUCCESS If \a name_buf was valid, the buffer now
+ contains a multi string of identities that matched. If \a
+ pn_idents was valid, it contains the number of identities
+ matched.
+
+ \retval KHM_ERROR_TOO_LONG No buffer was supplied or the supplied
+ buffer was insufficient. If \a pn_idents was valid, it
+ contains the number of identities.
+
+ \retval KHM_ERROR_INVALID_PARM None of the parameters \a name_buf,
+ \a pcb_buf and \a pn_idents were supplied, or \a pcb_buf was
+ NULL when \a name_buf was not.
+
+ \note Calling this function to obtain the required size of the
+ buffer and then calling it with a that sized buffer is not
+ guaranteed to work since the list of identities may change
+ between the two calls.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_enum(khm_int32 and_flags,
+ khm_int32 eq_flags,
+ wchar_t * name_buf,
+ khm_size * pcb_buf,
+ khm_size * pn_idents);
+
+/*! \brief Refresh identity attributes based on root credential set
+
+ Several flags in an identity are dependent on the credentials that
+ are associated with it in the root credential set. In addition,
+ other flags in an identity depend on external factors that need to
+ be verfied once in a while. This API goes through the root
+ credential set as well as consulting the identity provider to
+ update an identity.
+
+ \see kcdb_identity_refresh()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_refresh(khm_handle vid);
+
+/*! \brief Refresh all identities
+
+ Equivalent to calling kcdb_identity_refresh() for all active
+ identities.
+
+ \see kcdb_identityt_refresh()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_identity_refresh_all(void);
+
+/* KSMG_KCDB_IDENT notifications are structured as follows:
+ type=KMSG_KCDB
+ subtype=KMSG_KCDB_IDENT
+ uparam=one of KCDB_OP_*
+ blob=handle to identity in question */
+
+/*@}*/
+
+
+/*********************************************************************/
+
+
+/*!
+\defgroup kcdb_creds Credential sets and individual credentials
+
+@{
+*/
+
+
+/*! \brief Credentials process function
+
+ This function is called for each credential in a credential set
+ when supplied to kcdb_credset_apply(). It should return
+ KHM_ERROR_SUCCESS to continue the operation, or any other value to
+ terminate the processing.
+
+ \see kcdb_credset_apply()
+*/
+typedef khm_int32
+(KHMAPI *kcdb_cred_apply_func)(khm_handle cred,
+ void * rock);
+
+/*! \brief Credentials filter function.
+
+ Should return non-zero if the credential passed as \a cred is to
+ be "accepted". The precise consequence of a non-zero return value
+ is determined by the individual function that this call back is
+ passed into.
+
+ This function should not call any other function which may modify
+ \a cred.
+
+ \see kcdb_credset_collect_filtered()
+ \see kcdb_credset_extract_filtered()
+*/
+typedef khm_int32
+(KHMAPI *kcdb_cred_filter_func)(khm_handle cred,
+ khm_int32 flags,
+ void * rock);
+
+/*! \brief Credentials compare function.
+
+ Asserts a weak ordering on the credentials that are passed in as
+ \a cred1 and \a cred2. It should return:
+
+ - a negative value if \a cred1 < \a cred2
+ - zero if \a cred1 == \a cred2
+ - a postive value if \a cred1 > \a cred2
+ \see kcdb_credset_sort()
+*/
+typedef khm_int32
+(KHMAPI *kcdb_cred_comp_func)(khm_handle cred1,
+ khm_handle cred2,
+ void * rock);
+
+/*! \defgroup kcdb_credset Credential sets */
+/*@{*/
+
+/*! \brief Create a credential set.
+
+ Credential sets are temporary containers for credentials. These
+ can be used by plug-ins to store credentials while they are being
+ enumerated from an external source. Once all the credentials have
+ been collected into the credential set, the plug-in may call
+ kcdb_credset_collect() to collect the credentials into the root
+ credential store.
+
+ The user interface will only display credentials that are in the
+ root credential store. No notifications are generated for changes
+ to a non-root credential set.
+
+ Use kcdb_credset_delete() to delete the credential set once it is
+ created.
+
+ \see kcdb_credset_delete()
+ \see kcdb_credset_collect()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_create(khm_handle * result);
+
+/** \brief Delete a credential set
+
+ \see kcdb_credset_create()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_delete(khm_handle credset);
+
+/** \brief Collect credentials from a credential set to another credential set.
+
+ Collecting a subset of credentials from credential set \a cs_src
+ into credential set \a cs_dest involves the following steps:
+
+ - Select all credentials from \a cs_src that matches the \a
+ identity and \a type specified in the function call and add them
+ to the \a cs_dest credential set if they are not there already.
+ Note that if neither credential set is not the root credential
+ store, then the credentials will be added by reference, while if
+ it is the root credential store, the credentials will be
+ duplicated, and the copies will be added to \a cs_dest.
+
+ - If a selected credential in \a cs_src already exists in \a
+ cs_dest, then update the credential in \a cs_dest with the
+ credential fields in \a cs_src. In other words, once a
+ credential is found to exist in both \a cs_src and \a cs_dest,
+ all the non-null fields from the credential in \a cs_src will be
+ copied to the credential in \a cs_dest. Fields which are null
+ (undefined) in \a cs_src and are non-null in \a cs_dest will be
+ left unmodified in \a cs_dest.
+
+ One notable exception is the credentials' flags. All flags in
+ \a cs_src which are not included in
+ ::KCDB_CRED_FLAGMASK_ADDITIVE will be copied to the
+ corresponding bits in the flags of \a cs_dest. However, flags
+ that are included in ::KCDB_CRED_FLAGMASK_ADDITIVE will be added
+ to the corresponding bits in \a cs_dest.
+
+ (See notes below)
+
+ - Remove all credentials from \a cs_dest that match the \a
+ identity and \a type that do not appear in \a cs_src. (see notes
+ below)
+
+ For performance reasons, plugins should use kcdb_credset_collect()
+ to update the root credentials store instead of adding and
+ removing individual credentials from the root store.
+
+ Only credentials that are associated with active identities are
+ affected by kcdb_credset_collect().
+
+ \param[in] cs_dest A handle to the destination credential set. If
+ this is \a NULL, then it is assumed to refer to the root
+ credential store.
+
+ \param[in] cs_src A handle to the source credential set. If this
+ is NULL, then it is assumed to refer to the root credential
+ store.
+
+ \param[in] identity A handle to an identity. Setting this to NULL
+ collects all identities in the credential set.
+
+ \param[in] type A credentials type. Setting this to
+ KCDB_CREDTYPE_ALL collects all credential types in the set.
+
+ \param[out] delta A bit mask that indicates the modifications that
+ were made to \a cs_dest as a result of the collect operation.
+ This is a combination of KCDB_DELTA_* values. This parameter
+ can be \a NULL if the value is not required.
+
+ \warning If \a identity and \a type is set to a wildcard, all
+ credentials in the root store that are not in this credentials
+ set will be deleted.
+
+ \note Two credentials \a A and \a B are considered equal if:
+ - They refer to the same identity
+ - Both have the same credential type
+ - Both have the same name
+
+ \note This is the only supported way of modifying the root
+ credential store.
+
+ \note \a cs_src and \a cs_dest can not refer to the same
+ credentials set.
+
+ \note The destination credential set cannot be sealed.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_collect(khm_handle cs_dest,
+ khm_handle cs_src,
+ khm_handle identity,
+ khm_int32 type,
+ khm_int32 * delta);
+
+/*! \brief Credentials were added
+ \see kcdb_credset_collect() */
+#define KCDB_DELTA_ADD 1
+
+/*! \brief Credentials were deleted
+ \see kcdb_credset_collect() */
+#define KCDB_DELTA_DEL 2
+
+/*! \brief Credentials were modified
+ \see kcdb_credset_collect() */
+#define KCDB_DELTA_MODIFY 4
+
+/*! \brief Indicates that the credential to be filtered is from the root store.
+
+ \see kcdb_credset_collect_filtered()
+*/
+#define KCDB_CREDCOLL_FILTER_ROOT 1
+
+/*! \brief Indicates that the credential to be filtered is from the source
+ credential set
+
+ \see kcdb_credset_collect_filtered() */
+#define KCDB_CREDCOLL_FILTER_SRC 2
+
+/*! \brief Indicates that the credential to be filtered is from the destination
+ credential set
+
+ \see kcdb_credset_collect_filtered() */
+#define KCDB_CREDCOLL_FILTER_DEST 4
+
+/*! \brief Collect credentials from one credential set to another using a filter.
+
+ Similar to kcdb_credset_collect() except instead of selecting
+ credentials by matching against an identity and/or type, a filter
+ function is called. If the filter function returns non-zero for a
+ credential, that credential is selected.
+
+ Credentials in the source and destination credential sets are
+ passed into the filter function. Depending on whether the
+ credential is in the source credential set or destination
+ credential set, the \a flag parameter may have either \a
+ KCDB_CREDCOLL_FILTER_SRC or \a KCDB_CREDCOLL_FILTER_DEST bits set.
+ Also, if either one of the credential sets is the root credential
+ store, then additionally \a KCDB_CREDCOLL_FILTER_ROOT would also
+ be set.
+
+ See the kcdb_credset_collect() documentation for explanations of
+ the \a cs_src, \a cs_dest and \a delta parameters which perform
+ identical functions.
+
+ \param[in] filter The filter of type ::kcdb_cred_filter_func
+ \param[in] rock A custom argument to be passed to the filter function.
+
+ \see kcdb_credset_collect()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_collect_filtered(khm_handle cs_dest,
+ khm_handle cs_src,
+ kcdb_cred_filter_func filter,
+ void * rock,
+ khm_int32 * delta);
+
+/*! \brief Flush all credentials from a credential set
+
+ Deletes all the crednetials from the credential set.
+
+ \param[in] credset A handle to a credential set. Cannot be NULL.
+
+ \note The credential set cannot be sealed
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_flush(khm_handle credset);
+
+/*! \brief Extract credentials from one credential set to another
+
+ Credentials from the source credential set are selected based on
+ the \a identity and \a type arguements. If a credential is
+ matched, then it is added to the \a destcredset.
+
+ If the \a sourcecredset is the root credential set, the added
+ credentials are copies of the actual credentials in the root
+ credential set. Otherwise the credentials are references to the
+ original credentials in the \a sourcecredset .
+
+ \param[in] destcredset Destination credential set. Must be valid.
+
+ \param[in] sourcecredset The source credential set. If set to
+ NULL, extracts from the root credential set.
+
+ \param[in] identity The identity to match in the source credential
+ set. If set to NULL, matches all identities.
+
+ \param[in] type The credential type to match in the source credential set.
+ If set to KCDB_TYPE_INVALID, matches all types.
+
+ \note This function does not check for duplicate credentials.
+
+ \note The destination credential set cannot be sealed.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_extract(khm_handle destcredset,
+ khm_handle sourcecredset,
+ khm_handle identity,
+ khm_int32 type);
+
+/*! \brief Extract credentials from one credential set to another using a filter.
+
+ Similar to kcdb_credset_extract() except a filter function is used
+ to determine which credentials should be selected.
+
+ \param[in] rock A custom argument to be passed in to the filter function.
+
+ \note The destination credential set cannot be sealed.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_extract_filtered(khm_handle destcredset,
+ khm_handle sourcecredset,
+ kcdb_cred_filter_func filter,
+ void * rock);
+
+/*! \brief Retrieve a held reference to a credential in a credential set based on index.
+
+ \param[in] idx The index of the credential to retrieve. This is a
+ zero based index which goes from 0 ... (size of credset - 1).
+
+ \param[out] cred The held reference to a credential. Call
+ kcdb_cred_release() to release the credential.
+
+ \retval KHM_ERROR_SUCCESS Success. \a cred has a held reference to the credential.
+ \retval KHM_ERROR_OUT_OF_BOUNDS The index specified in \a idx is out of bounds.
+ \retval KHM_ERROR_DELETED The credential at index \a idx has been marked as deleted.
+
+ \see kcdb_cred_release()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_get_cred(khm_handle credset,
+ khm_int32 idx,
+ khm_handle * cred);
+
+/*! \brief Search a credential set for a specific credential
+
+ The credential set indicated by \a credset is searched for a
+ credential that satisfies the predicate function \a f. Each
+ credential starting at \a idx_start is passed into the predicate
+ function until it returns a non-zero value. At this point, that
+ credential is passed in to the \a cred parameter, and the index of
+ the credential is passed into the \a idx parameter.
+
+ \param[in] credset The credential set to search on. Specify NULL
+ if you want to search teh root credential set.
+
+ \param[in] idx_start The index at which to start the search after.
+ The first credential passed to the predicate function will be
+ at \a idx_start + 1. Specify -1 to start from the beginning
+ of the credential set.
+
+ \param[in] f The predicate function. The \a flags parameter of
+ the predicate function will always receive 0.
+
+ \param[in] rock An opaque parameter to be passed to the predicate
+ function \a f.
+
+ \param[out] cred A held reference to the credential that satisfied
+ the predicate function or NULL if no such credential was
+ found. Note that if a valid credential is returned, the
+ calling function must release the credential using
+ kcdb_cred_release().
+
+ \param[out] idx The index of the credential passed in \a cred.
+ Specify NULL if the index is not required.
+
+ \retval KHM_ERROR_SUCCESS A credential that satisfied the
+ predicate function was found and was assigned to \a cred.
+
+ \retval KHM_ERROR_NOT_FOUND No credential was found that matched
+ the predicate function.
+
+ \note When querying credential sets that are shared between
+ threads, it is possible that another thread modifies the
+ credential set between successive calls to
+ kcdb_credset_find_filtered(). Therefore a continued sequences of
+ searches are not guaranteed to exhastively cover the
+ credential set nor to not return duplicate matches. Duplicate
+ matches are possible if the order of the credentials in the
+ set was changed.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_find_filtered(khm_handle credset,
+ khm_int32 idx_start,
+ kcdb_cred_filter_func f,
+ void * rock,
+ khm_handle * cred,
+ khm_int32 * idx);
+
+/*! \brief Find matching credential
+
+ Searches a credential set for a credential that matches the
+ specified credential. For a credential to be a match, it must
+ have the same identity, credential type and name.
+
+ \param[in] credset Credential set to search
+
+ \param[in] cred_src Credetial to search on
+
+ \param[out] cred_dest receieves the matching credential if the
+ search is successful. If a handle is returend, the
+ kcdb_cred_release() must be used to release the handle. If
+ the matching credential is not required, you can pass in NULL.
+
+ \retval KHM_ERROR_SUCCESS The search was successful. A credential
+ was assigned to \a cred_dest
+
+ \retval KHM_ERROR_NOT_FOUND A matching credential was not found.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_find_cred(khm_handle credset,
+ khm_handle cred_src,
+ khm_handle *cred_dest);
+
+
+/*! \brief Delete a credential from a credential set.
+
+ The credential at index \a idx will be deleted. All the
+ credentials that are at indices \a idx + 1 and above will be moved
+ down to fill the gap and the size of the credential set will
+ decrease by one.
+
+ Use kcdb_credset_del_cred_ref() to delete a credential by
+ reference. Using kcdb_credset_del_cred() is faster than
+ kcdb_credset_del_cred_ref().
+
+ If you call kcdb_credset_del_cred() or kcdb_credset_del_cred_ref()
+ from within kcdb_credset_apply(), the credential will only be
+ marked as deleted. They will not be removed. This means that the
+ size of the credential set will not decrease. To purge the
+ deleted credentials from the set, call kcdb_credset_purge() after
+ kcdb_credset_apply() completes.
+
+ \note The credential set cannot be sealed.
+
+ \see kcdb_credset_del_cred_ref()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_del_cred(khm_handle credset,
+ khm_int32 idx);
+
+/*! \brief Delete a credential from a credential set by reference.
+
+ See kcdb_credset_del_cred() for description of what happens when a
+ credential is deleted from a credential set.
+
+ \note The credential set cannot be sealed.
+
+ \see kcdb_credset_del_cred()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_del_cred_ref(khm_handle credset,
+ khm_handle cred);
+
+/*! \brief Add a credential to a credential set.
+
+ The credential is added by reference. In other words, no copy of
+ the credential is made.
+
+ \param[in] idx Index of the new credential. This must be a value
+ in the range 0..(previous size of credential set) or -1. If
+ -1 is specifed, then the credential is appended at the end of
+ the set.
+
+ \note The credential set cannot be sealed.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_add_cred(khm_handle credset,
+ khm_handle cred,
+ khm_int32 idx);
+
+/*! \brief Get the number of credentials in a credential set.
+
+ Credentials in a credential set may be volatile. When
+ kcdb_credeset_get_size() is called, the credential set is
+ compacted to only include credentials that are active at the time.
+ However, when you are iterating through the credential set, it
+ might be the case that some credentials would get marked as
+ deleted. These credentials will remain in the credential set
+ until the credential set is discarded or another call to
+ kcdb_credset_get_size() or kdcb_credset_purge() is made.
+
+ If the credential set is sealed, then it will not be compacted and
+ will include deleted credentials as well.
+
+ \see kcdb_credset_purge()
+ \see kcdb_credset_get_cred()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_get_size(khm_handle credset,
+ khm_size * size);
+
+/*! \brief Removes credentials that have been marked as deleted from a credential set.
+
+ See description of \a kcdb_credset_purge() for a description of
+ what happens when credntials that are contained in a credential
+ set are deleted by an external entity.
+
+ \note The credential set cannot be sealed.
+
+ \see kcdb_credset_get_size()
+ \see kcdb_credset_get_cred()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_purge(khm_handle credset);
+
+/*! \brief Applies a function to all the credentials in a credentials set
+
+ The given function is called for each credential in a credential
+ set. With each iteration, the function is called with a handle to
+ the credential and the user defined parameter \a rock. If the
+ function returns anything other than KHM_ERROR_SUCCESS, the
+ processing stops.
+
+ \param[in] credset The credential set to apply the function to, or
+ NULL if you want to apply this to the root credential set.
+
+ \param[in] f Function to call for each credential
+
+ \param[in] rock An opaque parameter which is to be passed to 'f'
+ as the second argument.
+
+ \retval KHM_ERROR_SUCCESS All the credentials were processed.
+
+ \retval KHM_ERROR_EXIT The supplied function signalled the
+ processing to be aborted.
+
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_apply(khm_handle credset,
+ kcdb_cred_apply_func f,
+ void * rock);
+
+/*! \brief Sort the contents of a credential set.
+
+ \param[in] rock A custom argument to be passed in to the \a comp function.
+
+ \note The credential set cannot be sealed.
+
+ \see kcdb_cred_comp_generic()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_sort(khm_handle credset,
+ kcdb_cred_comp_func comp,
+ void * rock);
+
+/*! \brief Seal a credential set
+
+ Sealing a credential set makes it read-only. To unseal a
+ credential set, call kcdb_credset_unseal().
+
+ Sealing is an additive operation. kcdb_credset_seal() can be
+ called muliple times. However, for every call to
+ kcdb_credset_seal() a call to kcdb_credset_unseal() must be made
+ to undo the seal. The credential set will become unsealed when
+ all the seals are released.
+
+ Once sealed, the credential set will not allow any operation that
+ might change its contents. However, a selaed credential set can
+ still be delted.
+
+ \see kcdb_credset_unseal()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_seal(khm_handle credset);
+
+/*! \brief Unseal a credential set
+
+ Undoes what kcdb_credset_seal() did. This does not guarantee that
+ the credential set is unsealed since there may be other seals.
+
+ \see kcdb_credset_seal()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credset_unseal(khm_handle credset);
+
+/*! \brief Defines a sort criterion for kcdb_cred_comp_generic()
+
+ \see kcdb_cred_comp_generic()
+*/
+typedef struct tag_kcdb_cred_comp_field {
+ khm_int32 attrib; /*!< a valid attribute ID */
+ khm_int32 order; /*!< one of KCDB_CRED_COMP_INCREASING or
+ KCDB_CRED_COMP_DECREASING. Optionally,
+ KCDB_CRED_COMP_INITIAL_FIRST may be combined
+ with either. */
+} kcdb_cred_comp_field;
+
+/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field
+
+ Sorts lexicographically ascending by string representation of field.
+*/
+#define KCDB_CRED_COMP_INCREASING 0
+
+/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field
+
+ Sorts lexicographically descending by string representation of
+ field.
+ */
+#define KCDB_CRED_COMP_DECREASING 1
+
+/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field
+
+ Any credentials which have the ::KCDB_CRED_FLAG_INITIAL will be
+ grouped above any that don't.
+
+ If that does not apply, then credentials from the primary
+ credentials type will be sorted before others.
+*/
+#define KCDB_CRED_COMP_INITIAL_FIRST 2
+
+/*! \brief Defines the sort criteria for kcdb_cred_comp_generic()
+
+ \see kcdb_cred_comp_generic()
+*/
+typedef struct tag_kcdb_cred_comp_order {
+ khm_int32 nFields;
+ kcdb_cred_comp_field * fields;
+} kcdb_cred_comp_order;
+
+/*! \brief A generic compare function for comparing credentials.
+
+ This function can be passed as a parameter to kcdb_credset_sort().
+
+ The \a rock parameter to this function should be a pointer to a
+ ::kcdb_cred_comp_order object. The \a fields member of the
+ ::kcdb_cred_comp_order object should point to an array of
+ ::kcdb_cred_comp_field objects, each of which specifies the sort
+ order in decreasing order of priority. The number of
+ ::kcdb_cred_comp_field objects in the array should correspond to
+ the \a nFields member in the ::kcdb_cred_comp_order object.
+
+ The array of ::kcdb_cred_comp_field objects define the sort
+ criteria, in order. The \a attrib member should be a valid
+ attribute ID, while the \a order member determines whether the
+ sort order is increasing or decreasing. The exact meaning or
+ increasing or decreasing depends on the data type of the
+ attribute.
+
+ \param[in] rock a pointer to a ::kcdb_cred_comp_order object
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_comp_generic(khm_handle cred1,
+ khm_handle cred2,
+ void * rock);
+
+/*@}*/
+
+/*! \defgroup kcdb_cred Credentials */
+/*@{*/
+
+/*! \brief Maximum number of characters in a credential name */
+#define KCDB_CRED_MAXCCH_NAME 256
+
+/*! \brief Maximum number of bytes in a credential name */
+#define KCDB_CRED_MAXCB_NAME (sizeof(wchar_t) * KCDB_CRED_MAXCCH_NAME)
+
+/*! \brief Marked as deleted */
+#define KCDB_CRED_FLAG_DELETED 0x00000008
+
+/*! \brief Renewable */
+#define KCDB_CRED_FLAG_RENEWABLE 0x00000010
+
+/*! \brief Initial
+
+ Initial credentials form the basis of an identity. Some
+ properties of an initial credential, such as being renewable, are
+ directly inherited by the identity. An identity is also
+ automatically considered valid if it contains a valid initial
+ credential.
+ */
+#define KCDB_CRED_FLAG_INITIAL 0x00000020
+
+/*! \brief Expired
+
+ The credential's lifetime has ended.
+ */
+#define KCDB_CRED_FLAG_EXPIRED 0x00000040
+
+/*! \brief Invalid
+
+ The credential can no longer serve its intended function. This
+ may be because it is expired and is not renewable, or its
+ renewable time period has also expired, or for some other reason.
+ */
+#define KCDB_CRED_FLAG_INVALID 0x00000080
+
+/*! \brief Credential is selected
+
+ Indicates that the credential is selected. Note that using this
+ flag may be subject to race conditions.
+ */
+#define KCDB_CRED_FLAG_SELECTED 0x00000100
+
+/*! \brief Bitmask indicating all known credential flags
+ */
+#define KCDB_CRED_FLAGMASK_ALL 0x0000ffff
+
+/*! \brief Bitmask indicating dditive flags
+
+ Additive flags are special flags which are added to exiting
+ credentials based on new credentials when doing a collect
+ operation. See details on kcdb_credset_collect()
+
+ \see kcdb_credset_collect()
+*/
+#define KCDB_CRED_FLAGMASK_ADDITIVE KCDB_CRED_FLAG_SELECTED
+
+/*! \brief Generic credentials request
+
+ This data structure is used as the format for a generic
+ credentials reqeust for a ::KMSG_KCDB_REQUEST message. A plugin
+ typically publishes this message so that a credentials provider
+ may handle it and in response, obtain the specified credential.
+
+ While the \a identity, \a type and \a name members of the
+ structure are all optional, typically one would specify all three
+ or at least two for a credential provider to be able to provide
+ the credential unambigously.
+
+ Credential providers do not need to respond to ::KMSG_KCDB_REQUEST
+ messages. However, if they do, they should make sure that they
+ are the only credential provider that is responding by setting the
+ \a semaphore member to a non-zero value. The \a semaphore is set
+ to zero when a request is initially sent out. When incrementing
+ the semaphore, the plugin should use a thread safe mechanism to
+ ensure that there are no race conditions that would allow more
+ than one provider to respond to the message.
+ */
+typedef struct tag_kcdb_cred_request {
+ khm_handle identity; /*!< Identity of the credential. Set
+ to NULL if not specified. */
+ khm_int32 type; /*!< Type of the credential. Set to
+ KCDB_CREDTYPE_INVALID if not
+ specified. */
+ wchar_t * name; /*!< Name of the credential. Set to
+ NULL if not specified. */
+
+ khm_handle dest_credset; /*!< If non-NULL, instructs whoever is
+ handling the request that the
+ credential thus obtained be placed
+ in this credential set in addition
+ to whereever it may place newly
+ acquired credentials. Note that
+ while this can be NULL if the new
+ credential does not need to be
+ placed in a credential set, it can
+ not equal the root credential
+ set. */
+
+ void * vparam; /*!< An unspecified
+ parameter. Specific credential types
+ may specify how this field is to be
+ used. */
+
+ long semaphore; /*!< Incremented by one when this
+ request is answered. Only one
+ credential provider is allowed to
+ answer a ::KMSG_KCDB_REQUEST
+ message. Initially, when the
+ message is sent out, this member
+ should be set to zero. */
+} kcdb_cred_request;
+
+/*! \brief Create a new credential
+
+ \param[in] name Name of credential. \a name cannot be NULL and cannot
+ exceed \a KCDB_CRED_MAXCCH_NAME unicode characters including the
+ \a NULL terminator.
+ \param[in] identity A reference to an identity.
+ \param[in] cred_type A credentials type identifier for the credential.
+ \param[out] result Gets a held reference to the newly created credential.
+ Call kcdb_cred_release() or kcdb_cred_delete() to release the
+ reference.
+ \see kcdb_cred_release()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_create(wchar_t * name,
+ khm_handle identity,
+ khm_int32 cred_type,
+ khm_handle * result);
+
+/*! \brief Duplicate an existing credential.
+
+ \param[out] newcred A held reference to the new credential if the call
+ succeeds.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_dup(khm_handle cred,
+ khm_handle * newcred);
+
+/*! \brief Updates one credential using field values from another
+
+ All fields that exist in \a vsrc will get copied to \a vdest and will
+ overwrite any values that are already there in \a vdest. However any
+ values that exist in \a vdest taht do not exist in \a vsrc will not be
+ modified.
+
+ \retval KHM_ERROR_SUCCESS vdest was successfully updated
+ \retval KHM_ERROR_EQUIVALENT all fields in vsrc were present and equivalent in vdest
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_update(khm_handle vdest,
+ khm_handle vsrc);
+
+/*! \brief Set an attribute in a credential by name
+
+ \param[in] cbbuf Number of bytes of data in \a buffer. The
+ individual data type handlers may copy in less than this many
+ bytes in to the credential.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_set_attrib(khm_handle cred,
+ wchar_t * name,
+ void * buffer,
+ khm_size cbbuf);
+
+/*! \brief Set an attribute in a credential by attribute id
+
+ \param[in] buffer A pointer to a buffer containing the data to
+ assign to the attribute. Setting this to NULL has the effect
+ of removing any data that is already assigned to the
+ attribute. If \a buffer is non-NULL, then \a cbbuf should
+ specify the number of bytes in \a buffer.
+
+ \param[in] cbbuf Number of bytes of data in \a buffer. The
+ individual data type handlers may copy in less than this many
+ bytes in to the credential.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_set_attr(khm_handle cred,
+ khm_int32 attr_id,
+ void * buffer,
+ khm_size cbbuf);
+
+/*! \brief Get an attribute from a credential by name.
+
+ \param[in] buffer The buffer that is to receive the attribute
+ value. Set this to NULL if only the required buffer size is
+ to be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+
+ \note Set both \a buffer and \a cbbuf to NULL if only the
+ existence of the attribute is to be checked. If the attribute
+ exists in this credential then the function will return
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_attrib(khm_handle cred,
+ wchar_t * name,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * cbbuf);
+
+/*! \brief Get an attribute from a credential by attribute id.
+
+ \param[in] buffer The buffer that is to receive the attribute
+ value. Set this to NULL if only the required buffer size is
+ to be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+
+ \param[out] attr_type Receives the data type of the attribute.
+ Set this to NULL if the type is not required.
+
+ \note Set both \a buffer and \a cbbuf to NULL if only the
+ existence of the attribute is to be checked. If the attribute
+ exists in this credential then the function will return
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_attr(khm_handle cred,
+ khm_int32 attr_id,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * cbbuf);
+
+/*! \brief Get the name of a credential.
+
+ \param[in] buffer The buffer that is to receive the credential
+ name. Set this to NULL if only the required buffer size is to
+ be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_name(khm_handle cred,
+ wchar_t * buffer,
+ khm_size * cbbuf);
+
+/*! \brief Get the string representation of a credential attribute.
+
+ A shortcut function which generates the string representation of a
+ credential attribute directly.
+
+ \param[in] vcred A handle to a credential
+
+ \param[in] attr_id The attribute to retrieve
+
+ \param[out] buffer A pointer to a string buffer which receives the
+ string form of the attribute. Set this to NULL if you only
+ want to determine the size of the required buffer.
+
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,
+ holds the size of the buffer pointed to by \a buffer, and on
+ exit, receives the actual number of bytes that were copied.
+
+ \param[in] flags Flags for the string conversion. Can be set to
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is
+ KCDB_TS_LONG.
+
+ \retval KHM_ERROR_SUCCESS Success
+ \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid
+ or was not defined for this credential
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid
+ \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the
+ supplied buffer was insufficient
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_attr_string(khm_handle vcred,
+ khm_int32 attr_id,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags);
+
+/*! \brief Get the string representation of a credential attribute by name.
+
+ A shortcut function which generates the string representation of a
+ credential attribute directly.
+
+ \param[in] vcred A handle to a credential
+
+ \param[in] attrib The name of the attribute to retrieve
+
+ \param[out] buffer A pointer to a string buffer which receives the
+ string form of the attribute. Set this to NULL if you only
+ want to determine the size of the required buffer.
+
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,
+ holds the size of the buffer pointed to by \a buffer, and on
+ exit, receives the actual number of bytes that were copied.
+
+ \param[in] flags Flags for the string conversion. Can be set to
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is
+ KCDB_TS_LONG.
+
+ \see kcdb_cred_get_attr_string()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_attrib_string(khm_handle cred,
+ wchar_t * name,
+ wchar_t * buffer,
+ khm_size * cbbuf,
+ khm_int32 flags) ;
+
+
+/*! \brief Get a held reference to the identity associated with a credential
+
+ Use kcdb_identity_release() to release the reference that is
+ returned.
+
+ \see kcdb_identity_relase()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_identity(khm_handle cred,
+ khm_handle * identity);
+
+/*! \brief Set the identity of a credential
+
+ While it is ill-advised to change the identity of a credential
+ that has been placed in one or more credential sets, there can be
+ legitimate reasons for doing so. Only change the identity of a
+ credential that is not placed in a credential set or placed in a
+ credential set that is only used by a single entity.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_set_identity(khm_handle vcred,
+ khm_handle id);
+
+/*! \brief Get the serial number for the credential.
+
+ Each credential gets assigned a serial number at the time it is
+ created. This will stay with the credential for its lifetime.
+
+ \param[out] pserial Receives the serial number. Cannot be NULL.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_serial(khm_handle cred,
+ khm_ui_8 * pserial);
+
+/*! \brief Get the type of the credential.
+
+ The returned type is a credential type. Doh.
+
+ \param[out] type Receives the type. Cannot be NULL.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_type(khm_handle cred,
+ khm_int32 * type);
+
+/*! \brief Retrieve flags from a credential
+
+ The flags returned will be place in the location pointed to by \a
+ flags. Note that the specified credential must be an active
+ credential for the operation to succeed. This means the
+ ::KCDB_CRED_FLAG_DELETED will never be retured by this function.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_get_flags(khm_handle cred,
+ khm_int32 * flags);
+
+/*! \brief Set the flags of a credential
+
+ The flags specified in the \a mask parameter will be set to the
+ values specified in the \a flags parameter. The flags that are
+ not included in \a mask will not be modified.
+
+ This function can not be used to set the ::KCDB_CRED_FLAG_DELETED
+ flag. If this bit is specified in either \a flags or \a mask, it
+ will be ignored.
+
+ \see ::KCDB_CRED_FLAGMASK_ALL
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_set_flags(khm_handle cred,
+ khm_int32 flags,
+ khm_int32 mask);
+
+/*! \brief Hold a reference to a credential.
+
+ Use kcdb_cred_release() to release the reference.
+
+ \see kcdb_cred_release()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_hold(khm_handle cred);
+
+/*! \brief Release a held reference to a credential.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_release(khm_handle cred);
+
+/*! \brief Delete a credential.
+
+ The credential will be marked for deletion and will continue to
+ exist until all held references are released. If the credential
+ is bound to a credential set or the root credential store, it will
+ be removed from the respective container.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_cred_delete(khm_handle cred);
+
+/*! \brief Compare an attribute of two credentials by name.
+
+ \return The return value is dependent on the type of the attribute
+ and indicate a weak ordering of the attribute values of the two
+ credentials. If one or both credentials do not contain the
+ attribute, the return value is 0, which signifies that no ordering
+ can be determined.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_creds_comp_attrib(khm_handle cred1,
+ khm_handle cred2,
+ wchar_t * name);
+
+/*! \brief Compare an attribute of two credentials by attribute id.
+
+ \return The return value is dependent on the type of the attribute
+ and indicate a weak ordering of the attribute values of the two
+ credentials. If one or both credentials do not contain the
+ attribute, the return value is 0, which signifies that no ordering
+ can be determined.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_creds_comp_attr(khm_handle cred1,
+ khm_handle cred2,
+ khm_int32 attr_id);
+
+/*! \brief Compare two credentials for equivalence
+
+ \return Non-zero if the two credentials are equal. Zero otherwise.
+ \note Two credentials are considered equal if all the following hold:
+ - Both refer to the same identity.
+ - Both have the same name.
+ - Both have the same type.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_creds_is_equal(khm_handle cred1,
+ khm_handle cred2);
+
+/*@}*/
+/*@}*/
+
+/********************************************************************/
+
+/*! \defgroup kcdb_type Credential attribute types */
+/*@{*/
+
+/*! \brief Convert a field to a string
+
+ Provides a string representation of a field in a credential. The
+ data buffer can be assumed to be valid.
+
+ On entry, \a s_buf can be NULL if only the required size of the
+ buffer is to be returned. \a pcb_s_buf should be non-NULL and
+ should point to a valid variable of type ::khm_size that will, on
+ entry, contain the size of the buffer pointed to by \a s_buf if \a
+ s_buf is not \a NULL, and on exit will contain the number of bytes
+ consumed in \a s_buf, or the required size of the buffer if \a
+ s_buf was NULL or the size of the buffer was insufficient.
+
+ The implementation should verify the parameters that are passed in
+ to the function.
+
+ The data pointed to by \a data should not be modified in any way.
+
+ \param[in] data Valid pointer to a block of data
+
+ \param[in] cb_data Number of bytes in data block pointed to by \a
+ data
+
+ \param[out] s_buf Buffer to receive the string representation of
+ data. If the data type flags has KCDB_TYPE_FLAG_CB_AUTO, then
+ this parameter could be set to KCDB_CBSIZE_AUTO. In this
+ case, the function should compute the size of the input buffer
+ assuming that the input buffer is valid.
+
+ \param[in,out] pcb_s_buf On entry, contains the size of the buffer
+ pointed to by \a s_buf, and on exit, contains the number of
+ bytes used by the string representation of the data including
+ the NULL terminator
+
+ \param[in] flags Flags for formatting the string
+
+ \retval KHM_ERROR_SUCCESS The string representation of the data
+ field was successfully copied to \a s_buf and the size of the
+ buffer used was copied to \a pcb_s_buf.
+
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid
+
+ \retval KHM_ERROR_TOO_LONG Either \a s_buf was \a NULL or the size
+ indicated by \a pcb_s_buf was too small to contain the string
+ representation of the value. The required size of the buffer
+ is in \a pcb_s_buf.
+
+ \note This documents the expected behavior of this prototype function
+
+ \see ::kcdb_type
+ */
+typedef khm_int32
+(KHMAPI *kcdb_dtf_toString)(const void * data,
+ khm_size cb_data,
+ wchar_t * s_buf,
+ khm_size * pcb_s_buf,
+ khm_int32 flags);
+
+/*! \brief Verifies whetehr the given buffer contains valid data
+
+ The function should examine the buffer and the size of the buffer
+ and determine whether or not the buffer contains valid data for
+ this data type.
+
+ The data field pointed to by \a data should not be modified in any
+ way.
+
+ \param[in] data A pointer to a data buffer
+
+ \param[in] cb_data The number of bytes in the data buffer. If the
+ data type flags has KCDB_TYPE_FLAG_CB_AUTO, then this
+ parameter could be set to KCDB_CBSIZE_AUTO. In this case, the
+ function should compute the size of the input buffer assuming
+ that the input buffer is valid.
+
+ \return TRUE if the data is valid, FALSE otherwise.
+
+ \note This documents the expected behavior of this prototype function
+
+ \see ::kcdb_type
+*/
+typedef khm_boolean
+(KHMAPI *kcdb_dtf_isValid)(const void * data,
+ khm_size cb_data);
+
+/*! \brief Compare two fields
+
+ Compare the two data fields and return a value indicating their
+ relative ordering. The return value follows the same
+ specification as strcmp().
+
+ Both data buffers that are passed in can be assumed to be valid.
+
+ None of the data buffers should be modified in any way.
+
+ \param[in] data_l Valid pointer to first data buffer
+
+ \param[in] cb_data_l Number of bytes in \a data_l. If the data
+ type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter
+ could be set to KCDB_CBSIZE_AUTO. In this case, the function
+ should compute the size of the input buffer assuming that the
+ input buffer is valid.
+
+ \param[in] data_r Valid pointer to second data buffer
+
+ \param[in] cb_data_r Number of bytes in \a data_r. If the data
+ type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter
+ could be set to KCDB_CBSIZE_AUTO. In this case, the function
+ should compute the size of the input buffer assuming that the
+ input buffer is valid.
+
+ \return The return value should be
+ - Less than zero if \a data_l &lt; \a data_r
+ - Equal to zero if \a data_l == \a data_r or if this data type can not be compared
+ - Greater than zero if \a data_l &gt; \a data_r
+
+ \note This documents the expected behavior of this prototype function
+
+ \see ::kcdb_type
+*/
+typedef khm_int32
+(KHMAPI *kcdb_dtf_comp)(const void * data_l,
+ khm_size cb_data_l,
+ const void * data_r,
+ khm_size cb_data_r);
+
+/*! \brief Duplicate a data field
+
+ Duplicates a data field. The buffer pointed to by \a data_src
+ contains a valid field. The function should copy the field with
+ appropriate adjustments to \a data_dst.
+
+ The \a data_dst parameter can be NULL if only the required size of
+ the buffer is needed. In this case, teh function should set \a
+ pcb_data_dst to the number of bytes required and then return
+ KHM_ERROR_TOO_LONG.
+
+ \param[in] data_src Pointer to a valid data buffer
+
+ \param[in] cb_data_src Number of bytes in \a data_src. If the data
+ type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter
+ could be set to KCDB_CBSIZE_AUTO. In this case, the function
+ should compute the size of the input buffer assuming that the
+ input buffer is valid.
+
+ \param[out] data_dst Poitner to destination buffer. Could be NULL
+ if only the required size of the destination buffer is to be
+ returned.
+
+ \param[in,out] pcb_data_dst On entry specifies the number of bytes
+ in \a data_dst, and on exit should contain the number of bytes
+ copied.
+
+ \retval KHM_ERROR_SUCCESS The data was successfully copied. The
+ number of bytes copied is in \a pcb_data_dst
+
+ \retval KHM_ERROR_INVALID_PARM One or more parameters is incorrect.
+
+ \retval KHM_ERROR_TOO_LONG Either \a data_dst was NULL or the size
+ of the buffer was insufficient. The required size is in \a
+ pcb_data_dst
+
+ \note This documents the expected behavior of this prototype function
+
+ \see ::kcdb_type
+ */
+typedef khm_int32
+(KHMAPI *kcdb_dtf_dup)(const void * data_src,
+ khm_size cb_data_src,
+ void * data_dst,
+ khm_size * pcb_data_dst);
+
+/*! \brief A data type descriptor.
+
+ Handles basic operation for a specific data type.
+
+ \see \ref cred_data_types
+*/
+typedef struct tag_kcdb_type {
+ wchar_t * name;
+ khm_int32 id;
+ khm_int32 flags;
+
+ khm_size cb_min;
+ khm_size cb_max;
+
+ kcdb_dtf_toString toString;
+ /*!< Provides a string representation for a value. */
+
+ kcdb_dtf_isValid isValid;
+ /*!< Returns true of the value is valid for this data type */
+
+ kcdb_dtf_comp comp;
+ /*!< Compare two values and return \a strcmp style return value */
+
+ kcdb_dtf_dup dup;
+ /*!< Duplicate a value into a secondary buffer */
+} kcdb_type;
+
+/*! \name Flags for kcdb_type::toString
+@{*/
+/*! \brief Specify that the short form of the string representation should be returned.
+
+ Flags for #kcdb_type::toString. The flag specifies how long the
+ string representation should be. The specific length of a short
+ or long description is not restricted and it is up to the
+ implementation to choose how to interpret the flags.
+
+ Usually, KCDB_TS_SHORT is specified when the amount of space that
+ is available to display the string is very restricted. It may be
+ the case that the string is truncated to facilitate displaying in
+ a constrainted space.
+*/
+#define KCDB_TS_SHORT 1
+
+/*! \brief Specify that the long form of the string representation should be returned
+
+ Flags for #kcdb_type::toString. The flag specifies how long the
+ string representation should be. The specific length of a short
+ or long description is not restricted and it is up to the
+ implementation to choose how to interpret the flags.
+
+*/
+#define KCDB_TS_LONG 0
+/*@}*/
+
+/*! \brief The maximum number of bytes allowed for a value of any type */
+#define KCDB_TYPE_MAXCB 16384
+
+/*! \name Flags for kcdb_type
+@{*/
+
+/*! \brief The type supports KCDB_CBSIZE_AUTO.
+
+ Used for types where the size of the object can be determined
+ through context or by the object content. Such as for objects
+ that have a fixed size or unicode strings that have a terminator.
+
+ This implies that ALL the object manipulation callbacks that are
+ defined in this type definition support the KCDB_CBSIZE_AUTO
+ value.
+*/
+#define KCDB_TYPE_FLAG_CB_AUTO 16
+
+/*! \brief The \a cb_min member is valid.
+
+ The \a cb_min member defines the minimum number of bytes that an
+ object of this type will consume.
+
+ \note If this flag is used in conjunction with \a
+ KCDB_TYPE_FLAG_CB_MAX then, \a cb_min must be less than or equal
+ to \a cb_max.
+*/
+#define KCDB_TYPE_FLAG_CB_MIN 128
+
+/*! \brief The \a cb_max member is valid.
+
+ The \a cb_max member defines the maximum number of bytes that an
+ object of this type will consume.
+
+ \note If this flag is used in conjunction with \a
+ KCDB_TYPE_FLAG_CB_MIN then, \a cb_min must be less than or
+ equal to \a cb_max. */
+#define KCDB_TYPE_FLAG_CB_MAX 256
+
+/*! \brief Denotes that objects of this type have a fixed size.
+
+ If this flags is specified, then the type definition must also
+ specify cb_min and cb_max, which must both be the same value.
+
+ \note Implies \a KCDB_TYPE_FLAG_CB_AUTO, \a KCDB_TYPE_FLAG_CB_MIN
+ and \a KCDB_TYPE_FLAG_CB_MAX. Pay special attention to the
+ implication of \a KCDB_TYPE_FLAG_AUTO.
+*/
+#define KCDB_TYPE_FLAG_CB_FIXED (KCDB_TYPE_FLAG_CB_AUTO|KCDB_TYPE_FLAG_CB_MIN|KCDB_TYPE_FLAG_CB_MAX)
+
+/*@}*/
+
+KHMEXP khm_int32 KHMAPI
+kcdb_type_get_id(wchar_t *name, khm_int32 * id);
+
+/*! \brief Return the type descriptor for a given type id
+
+ \param[out] info Receives a held reference to a type descriptor.
+ Use kcdb_type_release_info() to release the handle. If the \a
+ info parameter is NULL, the function returns KHM_ERROR_SUCCESS
+ if \a id is a valid type id, and returns KHM_ERROR_NOT_FOUND
+ otherwise.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_type_get_info(khm_int32 id, kcdb_type ** info);
+
+KHMEXP khm_int32 KHMAPI
+kcdb_type_release_info(kcdb_type * info);
+
+KHMEXP khm_int32 KHMAPI
+kcdb_type_get_name(khm_int32 id,
+ wchar_t * buffer,
+ khm_size * cbbuf);
+
+/*! \brief Register a credentials attribute type
+
+ The credentials type record pointed to by \a type defines a new
+ credential attribute type. The \a id member of \a type may be set
+ to KCDB_TYPE_INVALID to indicate that an attribute ID is to be
+ generated automatically.
+
+ \param[in] type The type descriptor
+ \param[out] new_id Receives the identifier for the credential attribute type.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_type_register(kcdb_type * type,
+ khm_int32 * new_id);
+
+/*! \brief Unregister a credential attribute type
+
+ Removes the registration for the specified credentials attribute
+ type.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_type_unregister(khm_int32 id);
+
+KHMEXP khm_int32 KHMAPI
+kcdb_type_get_next_free(khm_int32 * id);
+
+/*! \name Conversion functions
+@{*/
+/*! \brief Convert a time_t value to FILETIME
+*/
+KHMEXP void KHMAPI
+TimetToFileTime( time_t t, LPFILETIME pft );
+
+/*! \brief Convert a time_t interval to a FILETIME interval
+*/
+KHMEXP void KHMAPI
+TimetToFileTimeInterval(time_t t, LPFILETIME pft);
+
+/*! \brief Convert a FILETIME interval to seconds
+*/
+KHMEXP long KHMAPI
+FtIntervalToSeconds(LPFILETIME pft);
+
+/*! \brief Convert a FILETIME interval to milliseconds
+*/
+KHMEXP long KHMAPI
+FtIntervalToMilliseconds(LPFILETIME pft);
+
+/*! \brief Compare two FILETIME values
+
+ The return value is similar to the return value of strcmp(), based
+ on the comparison of the two FILETIME values.
+ */
+KHMEXP long KHMAPI
+FtCompare(LPFILETIME pft1, LPFILETIME pft2);
+
+/*! \brief Convert a FILETIME inverval to a string
+*/
+KHMEXP khm_int32 KHMAPI
+FtIntervalToString(LPFILETIME data,
+ wchar_t * buffer,
+ khm_size * cb_buf);
+
+/*! \brief Parse a string representing an interval into a FILETIME interval
+
+ The string is a localized string which should look like the
+ following:
+
+ \code
+ [number unit] [number unit]...
+ \endcode
+
+ where \a number is an integer while \a unit is a localized
+ (possibly abbreviated) unit specification. The value of the
+ described interval is calculated as the sum of each \a number in
+ \a units. For example :
+
+ \code
+ 1 hour 36 minutes
+ \endcode
+
+ would result in an interval specification that's equivalent to 1
+ hour and 36 minutes. Of course there is no restriction on the
+ order in which the \a number \a unit specifications are given and
+ the same unit may be repeated multiple times.
+
+ \retval KHM_ERROR_INVALID_PARM The given string was invalid or had
+ a token that could not be parsed. It can also mean that \a
+ pft was NULL or \a str was NULL.
+
+ \retval KHM_ERROR_SUCCESS The string was successfully parsed and
+ the result was placed in \a pft.
+*/
+KHMEXP khm_int32 KHMAPI
+IntervalStringToFt(FILETIME * pft, wchar_t * str);
+
+/*! \brief Return number of milliseconds till next representation change
+
+ Returns the number of milliseconds that must elapse away from the
+ interval specified in pft \a for the representation of pft to change
+ from whatever it is right now.
+
+ Returns 0 if the representation is not expected to change.
+*/
+KHMEXP long KHMAPI
+FtIntervalMsToRepChange(LPFILETIME pft);
+
+/*! \brief Convert a safe ANSI string to a Unicode string
+
+ The resulting string is guaranteed to be NULL terminated and
+ within the size limit set by \a cbwstr.
+
+ If the whole string cannot be converted, \a wstr is set to an
+ empty string.
+
+ \return the number of characters converted. This is always either
+ the length of the string \a astr or 0.
+*/
+KHMEXP int KHMAPI
+AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr);
+
+/*! \brief Convert a Unicode string to ANSI
+
+ The resulting string is guaranteed to be NULL terminated and
+ within the size limit set by \a cbdest.
+
+ \return the number of characters converted. This is always either
+ the length of the string \a src or 0.
+*/
+KHMEXP int KHMAPI
+UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src);
+/*@}*/
+
+/*! \name Standard type identifiers and names
+@{*/
+
+/*! Maximum identifier number */
+#define KCDB_TYPE_MAX_ID 255
+
+/*! \brief Invalid type
+
+ Used by functions that return a type identifier to indicate that
+ the returned type identifier is invalid. Also used to indicate
+ that a type identifier is not available */
+#define KCDB_TYPE_INVALID (-1)
+
+/*! \brief All types
+
+ Used by filters to indicate that all types are allowed.
+*/
+#define KCDB_TYPE_ALL KCDB_TYPE_INVALID
+
+#define KCDB_TYPE_VOID 0
+#define KCDB_TYPE_STRING 1
+#define KCDB_TYPE_DATE 2
+#define KCDB_TYPE_INTERVAL 3
+#define KCDB_TYPE_INT32 4
+#define KCDB_TYPE_INT64 5
+#define KCDB_TYPE_DATA 6
+
+#define KCDB_TYPENAME_VOID L"Void"
+#define KCDB_TYPENAME_STRING L"String"
+#define KCDB_TYPENAME_DATE L"Date"
+#define KCDB_TYPENAME_INTERVAL L"Interval"
+#define KCDB_TYPENAME_INT32 L"Int32"
+#define KCDB_TYPENAME_INT64 L"Int64"
+#define KCDB_TYPENAME_DATA L"Data"
+/*@}*/
+/*@}*/
+
+/********************************************************************/
+
+/*! \defgroup kcdb_credattr Credential attributes */
+/*@{*/
+
+/*! \brief Prototype callback function for computed data types.
+
+ If the flags for a particular attribute specifies that the value
+ is computed, then a callback function should be specified. The
+ callback function will be called with a handle to a credential
+ along with the attribute ID for the requested attribute. The
+ function should place the computed value in \a buffer. The size
+ of the buffer in bytes is specifed in \a cbsize. However, if \a
+ buffer is \a NULL, then the required buffer size should be placed
+ in \a cbsize.
+ */
+typedef khm_int32
+(KHMAPI *kcdb_attrib_compute_cb)(khm_handle cred,
+ khm_int32 id,
+ void * buffer,
+ khm_size * cbsize);
+
+/*! \brief Credential attribute descriptor
+
+ \see kcdb_attrib_register()
+*/
+typedef struct tag_kcdb_attrib {
+ wchar_t * name; /*!< Name. (Not localized,
+ required) */
+ khm_int32 id; /*!< Identifier. When registering,
+ this can be set to
+ ::KCDB_ATTR_INVALID if a unique
+ identifier is to be generated. */
+ khm_int32 alt_id; /*!< Alternate identifier. If the \a
+ flags specify
+ ::KCDB_ATTR_FLAG_ALTVIEW, then this
+ field should specify the identifier
+ of the canonical attribute from
+ which this attribute is derived. */
+ khm_int32 flags; /*!< Flags. Combination of \ref
+ kcdb_credattr_flags "attribute
+ flags" */
+ khm_int32 type; /*!< Type of the attribute. Must be valid. */
+ wchar_t * short_desc; /*!< Short description. (Localized,
+ optional) */
+ wchar_t * long_desc; /*!< Long description. (Localized,
+ optional) */
+
+ kcdb_attrib_compute_cb compute_cb;
+ /*!< Callback. Required if \a flags
+ specify ::KCDB_ATTR_FLAG_COMPUTED. */
+ khm_size compute_min_cbsize;
+ /*!< Minimum number of bytes required
+ to store this attribute. Required
+ if ::KCDB_ATTR_FLAG_COMPUTED is
+ specified.*/
+ khm_size compute_max_cbsize;
+ /*!< Maximum number of bytes required
+ to store this attribute. Required
+ if ::KCDB_ATTR_FLAG_COMPUTED is
+ specified.*/
+} kcdb_attrib;
+
+/*! \brief Retrieve the ID of a named attribute */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_get_id(wchar_t *name,
+ khm_int32 * id);
+
+/*! \brief Register an attribute
+
+ \param[out] new_id Receives the ID of the newly registered
+ attribute. If the \a id member of the ::kcdb_attrib object is
+ set to KCDB_ATTR_INVALID, then a unique ID is generated. */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_register(kcdb_attrib * attrib,
+ khm_int32 * new_id);
+
+/*! \brief Retrieve the attribute descriptor for an attribute
+
+ The descriptor that is returned must be released through a call to
+ kcdb_attrib_release_info()
+
+ If only the validity of the attribute identifier needs to be
+ checked, you can pass in NULL for \a attrib. In this case, if the
+ identifier is valid, then the funciton will return
+ KHM_ERROR_SUCCESS, otherwise it will return KHM_ERROR_NOT_FOUND.
+
+ \see kcdb_attrib_release_info()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_get_info(khm_int32 id,
+ kcdb_attrib ** attrib);
+
+/*! \brief Release an attribute descriptor
+
+ \see kcdb_attrib_get_info()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_release_info(kcdb_attrib * attrib);
+
+/*! \brief Unregister an attribute
+
+ Once an attribute ID has been unregistered, it may be reclaimed by
+ a subsequent call to kcdb_attrib_register().
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_unregister(khm_int32 id);
+
+/*! \brief Retrieve the description of an attribute
+
+ \param[in] flags Specify \a KCDB_TS_SHORT to retrieve the short description. */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_describe(khm_int32 id,
+ wchar_t * buffer,
+ khm_size * cbsize,
+ khm_int32 flags);
+
+/*! \brief Count attributes
+
+ Counts the number of attributes that match the given criteria.
+ The criteria is specified against the flags of the attribute. An
+ attribute is a match if its flags satisfy the condition below:
+
+ \code
+ (attrib.flags & and_flags) == (eq_flags & and_flags)
+ \endcode
+
+ The number of attributes that match are returned in \a pcount.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_get_count(khm_int32 and_flags,
+ khm_int32 eq_flags,
+ khm_size * pcount);
+
+/*! \brief List attribute identifiers
+
+ Lists the identifiers of the attributes that match the given
+ criteria. The criteria is specified against the flags of the
+ attribute. An attribute is a match if the following condition is
+ satisfied:
+
+ \code
+ (attrib.flags & and_flags) == (eq_flags & and_flags)
+ \endcode
+
+ The list of attributes found are copied to the \a khm_int32 array
+ specified in \a plist. The number of elements available in the
+ buffer \a plist is specified in \a pcsize. On exit, \a pcsize
+ will hold the actual number of attribute identifiers copied to the
+ array.
+
+ \param[in] and_flags See above
+ \param[in] eq_flags See above
+ \param[in] plist A khm_int32 array
+ \param[in,out] pcsize On entry, holds the number of elements
+ available in the array pointed to by \a plist. On exit, holds
+ the number of elements copied to the array.
+
+ \retval KHM_ERROR_SUCCESS The list of attribute identifiers have
+ been copied.
+ \retval KHM_ERROR_TOO_LONG The list was too long to fit in the
+ supplied buffer. As many elements as possible have been
+ copied to the \a plist array and the required number of
+ elements has been written to \a pcsize.
+
+ \note The \a pcsize parameter specifies the number of khm_int32
+ elements in the array and not the number of bytes in the
+ array. This is different from the usual size parameters used
+ in the NetIDMgr API.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_attrib_get_ids(khm_int32 and_flags,
+ khm_int32 eq_flags,
+ khm_int32 * plist,
+ khm_size * pcsize);
+
+/*! \defgroup kcdb_credattr_flags Attribute flags */
+/*@{*/
+/*! \brief The attribute is required */
+#define KCDB_ATTR_FLAG_REQUIRED 0x00000008
+
+/*! \brief The attribute is computed.
+
+ If this flag is set, the \a compute_cb, \a compute_min_cbsize and
+ \a compute_max_cbsize members of the ::kcdb_attrib attribute
+ descriptor must be assigned valid values.
+*/
+#define KCDB_ATTR_FLAG_COMPUTED 0x00000010
+
+/*! \brief System attribute.
+
+ This cannot be specified for a custom attribute. Implies that the
+ value of the attribute is given by the credentials database
+ itself.
+*/
+#define KCDB_ATTR_FLAG_SYSTEM 0x00000020
+
+/*! \brief Hidden
+
+ The attribute is not meant to be displayed to the user. Setting
+ this flag prevents this attribute from being listed in the list of
+ available data fields in the UI.
+*/
+#define KCDB_ATTR_FLAG_HIDDEN 0x00000040
+
+/*! \brief Property
+
+ The attribute is a property. The main difference between regular
+ attributes and properties are that properties are not allocated
+ off the credentials record. Hence, a property can not be used as
+ a credentials field. Other objects such as identities can hold
+ property sets. A property set can hold both regular attributes as
+ well as properties.
+*/
+#define KCDB_ATTR_FLAG_PROPERTY 0x00000080
+
+/*! \brief Volatile
+
+ A volatile property is one whose value changes often, such as
+ ::KCDB_ATTR_TIMELEFT. Some controls will make use of additional
+ logic to deal with such values, or not display them at all.
+ */
+#define KCDB_ATTR_FLAG_VOLATILE 0x00000100
+
+/*! \brief Alternate view
+
+ The attribute is actually an alternate representation of another
+ attribute. The Canonical attribute name is specified in \a
+ alt_id.
+
+ Sometimes a certain attribute may need to be represented in
+ different ways. You can register multiple attributes for each
+ view. However, you should also provide a canonical attribute for
+ whenever the canonical set of attributes of the credential is
+ required.
+ */
+#define KCDB_ATTR_FLAG_ALTVIEW 0x00000200
+/*@}*/
+
+/*! \defgroup kcdb_credattr_idnames Standard attribute IDs and names */
+/*@{*/
+
+/*! \name Attribute related constants */
+/*@{*/
+/*! \brief Maximum valid attribute ID */
+#define KCDB_ATTR_MAX_ID 255
+
+/*! \brief Minimum valid property ID */
+#define KCDB_ATTR_MIN_PROP_ID 4096
+
+/*! \brief Maximum number of properties */
+#define KCDB_ATTR_MAX_PROPS 128
+
+/*! \brief Maximum valid property ID */
+#define KCDB_ATTR_MAX_PROP_ID (KCDB_ATTR_MIN_PROP_ID + KCDB_ATTR_MAX_PROPS - 1)
+
+/*! \brief Invalid ID */
+#define KCDB_ATTR_INVALID (-1)
+
+/*! \brief First custom attribute ID */
+#define KCDB_ATTRID_USER 20
+
+/*@}*/
+
+/*!\name Attribute identifiers */
+/*@{*/
+/*! \brief Name of the credential
+
+ - \b Type: STRING
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM
+ */
+#define KCDB_ATTR_NAME 0
+
+/*! \brief The identity handle for the credential
+
+ - \b Type: INT64
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN
+
+ \note The handle returned in by specifying this attribute to
+ kcdb_cred_get_attr() or kcdb_cred_get_attrib() is not held.
+ While the identity is implicitly held for the duration that
+ the credential is held, it is not recommended to obtain a
+ handle to the identity using this method. Use
+ kcdb_cred_get_identity() instead.
+*/
+#define KCDB_ATTR_ID 1
+
+/*! \brief The name of the identity
+
+ - \b Type: STRING
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM
+ */
+#define KCDB_ATTR_ID_NAME 2
+
+/*! \brief The type of the credential
+
+ - \b Type: INT32
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN
+*/
+#define KCDB_ATTR_TYPE 3
+
+/*! \brief Type name for the credential
+
+ - \b Type: STRING
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM
+*/
+#define KCDB_ATTR_TYPE_NAME 4
+
+/*! \brief Name of the parent credential
+
+ - \b Type: STRING
+ - \b Flags: SYSTEM
+*/
+#define KCDB_ATTR_PARENT_NAME 5
+
+/*! \brief Issed on
+
+ - \b Type: DATE
+ - \b Flags: SYSTEM
+*/
+#define KCDB_ATTR_ISSUE 6
+
+/*! \brief Expires on
+
+ - \b Type: DATE
+ - \b Flags: SYSTEM
+*/
+#define KCDB_ATTR_EXPIRE 7
+
+/*! \brief Renewable period expires on
+
+ - \b Type: DATE
+ - \b Flags: SYSTEM
+*/
+#define KCDB_ATTR_RENEW_EXPIRE 8
+
+/*! \brief Time left till expiration
+
+ - \b Type: INTERVAL
+ - \b Flags: SYSTEM, COMPUTED, VOLATILE
+*/
+#define KCDB_ATTR_TIMELEFT 9
+
+#define KCDB_ATTR_RENEW_TIMELEFT 10
+
+/*! \brief Location of the credential
+
+ - \b Type: STRING
+ - \b Flags: SYSTEM
+*/
+#define KCDB_ATTR_LOCATION 11
+
+/*! \brief Lifetime of the credential
+
+ - \b Type: INTERVAL
+ - \b Flags: SYSTEM
+*/
+#define KCDB_ATTR_LIFETIME 12
+
+#define KCDB_ATTR_RENEW_LIFETIME 13
+
+/*! \brief Flags for the credential
+
+ - \b Type: INT32
+ - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN
+ */
+#define KCDB_ATTR_FLAGS 14
+
+/*@}*/
+
+/*!\name Attribute names */
+/*@{ */
+
+#define KCDB_ATTRNAME_NAME L"Name"
+#define KCDB_ATTRNAME_ID L"Identity"
+#define KCDB_ATTRNAME_ID_NAME L"IdentityName"
+#define KCDB_ATTRNAME_TYPE L"TypeId"
+#define KCDB_ATTRNAME_TYPE_NAME L"TypeName"
+#define KCDB_ATTRNAME_FLAGS L"Flags"
+
+#define KCDB_ATTRNAME_PARENT_NAME L"Parent"
+#define KCDB_ATTRNAME_ISSUE L"Issed"
+#define KCDB_ATTRNAME_EXPIRE L"Expires"
+#define KCDB_ATTRNAME_RENEW_EXPIRE L"RenewExpires"
+#define KCDB_ATTRNAME_TIMELEFT L"TimeLeft"
+#define KCDB_ATTRNAME_RENEW_TIMELEFT L"RenewTimeLeft"
+#define KCDB_ATTRNAME_LOCATION L"Location"
+#define KCDB_ATTRNAME_LIFETIME L"Lifetime"
+#define KCDB_ATTRNAME_RENEW_LIFETIME L"RenewLifetime"
+
+/*@}*/
+
+/*@}*/
+
+/*@}*/
+
+/*****************************************************************************/
+
+/*! \defgroup kcdb_credtype Credential types */
+/*@{*/
+
+/*! \brief Credential type descriptor */
+typedef struct tag_kcdb_credtype {
+ wchar_t * name; /*!< name (less than KCDB_MAXCB_NAME bytes) */
+ khm_int32 id;
+ wchar_t * short_desc; /*!< short localized description (less
+ than KCDB_MAXCB_SHORT_DESC
+ bytes) */
+ wchar_t * long_desc; /*!< long localized descriptionn (less
+ than KCDB_MAXCB_LONG_DESC
+ bytes) */
+ khm_handle sub; /*!< Subscription for credentials type
+ hander. This should be a valid
+ subscription constructed through
+ a call to
+ kmq_create_subscription() and
+ must handle KMSG_CRED messages
+ that are marked as being sent to
+ type specific subscriptions.
+
+ The subscription will be
+ automatically deleted with a call
+ to kmq_delete_subscription() when
+ the credentials type is
+ unregistered.*/
+
+#ifdef _WIN32
+ HICON icon;
+#endif
+} kcdb_credtype;
+
+/*! \brief Maximum value of a credential type identifier
+
+ Credential type identifiers are assigned serially unless the
+ process registering the credential type sets a specific identity.
+ The maximum identifier number places a hard limit to the number of
+ credential types that can be registered at one time, which is
+ KCDB_CREDTYPE_MAX_ID + 1.
+ */
+#define KCDB_CREDTYPE_MAX_ID 31
+
+/*! \brief Specify all credential types
+
+ This value is used by functions which filter credentials based on
+ credential types. Specifying this value tells the filter to
+ accept all credential types.
+ */
+#define KCDB_CREDTYPE_ALL (-1)
+
+/*! \brief Automatically determine a credential type identifier
+
+ Used with kcdb_credtype_register() to specify that the credential
+ type identifier should be automatically determined to avoid
+ collisions.
+ */
+#define KCDB_CREDTYPE_AUTO (-2)
+
+/*! \brief An invalid credential type
+
+ Even though any non positive credential type ID is invalid
+ anywhere where a specific credential type ID is required, this
+ value is provided for explicit indication that the credential type
+ is invalid. Also it makes code more readable to have a constant
+ that shouts out INVALID.
+
+*/
+#define KCDB_CREDTYPE_INVALID (-3)
+
+/*! \brief Macro predicate for testing whether a credtype is valid
+
+ Returns TRUE if the given credtype is valid. This is a safe
+ macro.
+*/
+#define KCDB_CREDTYPE_IS_VALID(t) ((t) >= 0)
+
+/*! \brief Register a credentials type.
+
+ The information given in the \a type parameter is used to register
+ a new credential type. Note that the \a name member of the \a
+ type should be unique among all credential types.
+
+ You can specify ::KCDB_CREDTYPE_AUTO as the \a id member of \a
+ type to let kcdb_credtype_register() determine a suitable
+ credential type identifier. You can subsequently call
+ kcdb_credtype_get_id() to retrieve the generated id or pass a
+ valid pointer to a khm_int32 type variable as \a new_id.
+
+ \param[in] type Credential type descriptor
+
+ \param[out] new_id The credential type identifier that this type
+ was registered as.
+
+ \retval KHM_ERROR_SUCCESS The credential type was successfully registered.
+
+ \retval KHM_ERROR_INVALID_PARM One or more of the parameters were invalid
+
+ \retval KHM_ERROR_TOO_LONG One or more of the string fields in \a
+ type exceeded the character limit for that field.
+
+ \retval KHM_ERROR_NO_RESOURCES When autogenerating credential type
+ identifiers, this value indicates that the maximum number of
+ credential types have been registered. No more registrations
+ can be accepted unless some credentials type is unregisred.
+
+ \retval KHM_ERROR_DUPLICATE The \a name or \a id that was
+ specified is already in use.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_register(kcdb_credtype * type,
+ khm_int32 * new_id);
+
+/*! \brief Return a held reference to a \a kcdb_credtype object describing the credential type.
+
+ The reference points to a static internal object of type \a
+ kcdb_credtype. Use the kcdb_credtype_release_info() function to
+ release the reference.
+
+ Also, the structure passed in as the \a type argument to
+ kcdb_credtype_register() is not valid as a credential type
+ descriptor. Use kcdb_credtype_get_info() to obtain the actual
+ credential type descriptor.
+
+ \param[in] id Credentials type identifier.
+
+ \param[out] type Receives the credentials descriptor handle. If
+ \a type is NULL, then no handle is returned. However, the
+ function will still return \a KHM_ERROR_SUCCESS if the \a id
+ parameter passed in is a valid credentials type identifier.
+
+ \see kcdb_credtype_release_info()
+ \see kcdb_credtype_register()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_get_info(khm_int32 id,
+ kcdb_credtype ** type);
+
+/*! \brief Release a reference to a \a kcdb_credtype object
+
+ Undoes the hold obtained on a \a kcdb_credtype object from a
+ previous call to kcdb_credtype_get_info().
+
+ \see kcdb_credtype_get_info()
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_release_info(kcdb_credtype * type);
+
+/*! \brief Unregister a credentials type
+
+ Undoes the registration performed by kcdb_credtype_register().
+
+ This should only be done when the credentials provider is being
+ unloaded.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_unregister(khm_int32 id);
+
+/*! \brief Retrieve the name of a credentials type
+
+ Given a credentials type identifier, retrieves the name. The name
+ is not localized and serves as a persistent identifier of the
+ credentials type.
+
+ \param[out] buf The buffer to receive the name. Could be \a NULL
+ if only the length of the buffer is required.
+
+ \param[in,out] cbbuf On entry, specifies the size of the buffer
+ pointed to by \a buf if \a buf is not NULL. On exit, contains
+ the number of bytes copied to \a buf or the required size of
+ the buffer.
+
+ \retval KHM_ERROR_SUCCESS The call succeeded.
+
+ \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied
+ buffer was not large enough. The required size is in \a cbbuf.
+
+ \retval KHM_ERROR_INVALID_PARM Invalid parameter.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_get_name(khm_int32 id,
+ wchar_t * buf,
+ khm_size * cbbuf);
+
+/*! \brief Retrieve the type specific subscription for a type
+
+ Given a credentials type, this function returns the credentials
+ type specific subcription. It may return NULL if the subscription
+ is not available.
+ */
+KHMEXP khm_handle KHMAPI
+kcdb_credtype_get_sub(khm_int32 id);
+
+/*! \brief Get the description of a credentials type
+
+ Unlike the name of a credential type, the description is localized.
+
+ \param[in] id Credentials type identifier
+
+ \param[out] buf Receives the description. Can bet set to NULL if
+ only the size of the buffer is required.
+
+ \param[in,out] cbbuf On entry, specifies the size of the buffer
+ pointed to by \a buf. On exit, specifies the required size of
+ the buffer or the number of bytes copied, depending on whether
+ the call succeeded or not.
+
+ \param[in] flags Specify ::KCDB_TS_SHORT if the short version of
+ the description is desired if there is more than one.
+
+ \retval KHM_ERROR_SUCCESS The call succeeded
+ \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied buffer was insufficient. The required size is specified in \a cbbuf.
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid.
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_describe(khm_int32 id,
+ wchar_t * buf,
+ khm_size * cbbuf,
+ khm_int32 flags);
+
+/*! \brief Look up the identifier of a credentials type by name
+
+ Given a name, looks up the identifier.
+
+ \param[in] name Name of the credentials type
+ \param[out] id Receives the identifier if the call succeeds
+
+ */
+KHMEXP khm_int32 KHMAPI
+kcdb_credtype_get_id(wchar_t * name,
+ khm_int32 * id);
+
+/*@}*/
+
+/*********************************************************************/
+
+/*! \defgroup kcdb_buf Generic access to buffer
+
+ Currently, credentials and identities both hold record data types.
+ This set of API's allow an application to access fields in the
+ records using a single interface. Note that credentials only
+ accept regular attributes while identities can hold both
+ attributes and properties.
+
+ Handles to credentials and identities are implicitly also handles
+ to records. Thus they can be directly used as such.
+*/
+/*@{*/
+
+/*! \brief Get an attribute from a record by attribute id.
+
+ \param[in] buffer The buffer that is to receive the attribute
+ value. Set this to NULL if only the required buffer size is
+ to be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+
+ \param[out] attr_type Receives the data type of the attribute.
+ Set this to NULL if the type is not required.
+
+ \note Set both \a buffer and \a cbbuf to NULL if only the
+ existence of the attribute is to be checked. If the attribute
+ exists in this record then the function will return
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_get_attr(khm_handle record,
+ khm_int32 attr_id,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcb_buf);
+
+/*! \brief Get an attribute from a record by name.
+
+ \param[in] buffer The buffer that is to receive the attribute
+ value. Set this to NULL if only the required buffer size is
+ to be returned.
+
+ \param[in,out] cbbuf The number of bytes available in \a buffer.
+ If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and
+ sets this to the required buffer size.
+
+ \note Set both \a buffer and \a cbbuf to NULL if only the
+ existence of the attribute is to be checked. If the attribute
+ exists in this record then the function will return
+ KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_get_attrib(khm_handle record,
+ wchar_t * attr_name,
+ khm_int32 * attr_type,
+ void * buffer,
+ khm_size * pcb_buf);
+
+/*! \brief Get the string representation of a record attribute.
+
+ A shortcut function which generates the string representation of a
+ record attribute directly.
+
+ \param[in] record A handle to a record
+
+ \param[in] attr_id The attribute to retrieve
+
+ \param[out] buffer A pointer to a string buffer which receives the
+ string form of the attribute. Set this to NULL if you only
+ want to determine the size of the required buffer.
+
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,
+ holds the size of the buffer pointed to by \a buffer, and on
+ exit, receives the actual number of bytes that were copied.
+
+ \param[in] flags Flags for the string conversion. Can be set to
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is
+ KCDB_TS_LONG.
+
+ \retval KHM_ERROR_SUCCESS Success
+ \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid
+ or was not defined for this record
+ \retval KHM_ERROR_INVALID_PARM One or more parameters were invalid
+ \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the
+ supplied buffer was insufficient
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_get_attr_string(khm_handle record,
+ khm_int32 attr_id,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags);
+
+/*! \brief Get the string representation of a record attribute by name.
+
+ A shortcut function which generates the string representation of a
+ record attribute directly.
+
+ \param[in] record A handle to a record
+
+ \param[in] attrib The name of the attribute to retrieve
+
+ \param[out] buffer A pointer to a string buffer which receives the
+ string form of the attribute. Set this to NULL if you only
+ want to determine the size of the required buffer.
+
+ \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry,
+ holds the size of the buffer pointed to by \a buffer, and on
+ exit, receives the actual number of bytes that were copied.
+
+ \param[in] flags Flags for the string conversion. Can be set to
+ one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is
+ KCDB_TS_LONG.
+
+ \see kcdb_cred_get_attr_string()
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_get_attrib_string(khm_handle record,
+ wchar_t * attr_name,
+ wchar_t * buffer,
+ khm_size * pcbbuf,
+ khm_int32 flags);
+
+/*! \brief Set an attribute in a record by attribute id
+
+ \param[in] cbbuf Number of bytes of data in \a buffer. The
+ individual data type handlers may copy in less than this many
+ bytes in to the record.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_set_attr(khm_handle record,
+ khm_int32 attr_id,
+ void * buffer,
+ khm_size cbbuf);
+
+/*! \brief Set an attribute in a record by name
+
+ \param[in] cbbuf Number of bytes of data in \a buffer. The
+ individual data type handlers may copy in less than this many
+ bytes in to the record.
+*/
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_set_attrib(khm_handle record,
+ wchar_t * attr_name,
+ void * buffer,
+ khm_size cbbuf);
+
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_hold(khm_handle record);
+
+KHMEXP khm_int32 KHMAPI
+kcdb_buf_release(khm_handle record);
+
+/*@}*/
+
+/********************************************************************/
+
+/* Notification operation constants */
+
+#define KCDB_OP_INSERT 1
+#define KCDB_OP_DELETE 2
+#define KCDB_OP_MODIFY 3
+#define KCDB_OP_ACTIVATE 4
+#define KCDB_OP_DEACTIVATE 5
+#define KCDB_OP_HIDE 6
+#define KCDB_OP_UNHIDE 7
+#define KCDB_OP_SETSEARCH 8
+#define KCDB_OP_UNSETSEARCH 9
+#define KCDB_OP_NEW_DEFAULT 10
+
+/*@}*/
+
+#endif
diff --git a/src/windows/identity/kcreddb/kcreddbinternal.h b/src/windows/identity/kcreddb/kcreddbinternal.h
new file mode 100644
index 0000000..699954c
--- /dev/null
+++ b/src/windows/identity/kcreddb/kcreddbinternal.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCREDDBINTERNAL_H__
+#define __KHIMAIRA_KCREDDBINTERNAL_H__
+
+#include<windows.h>
+#include<kcreddb.h>
+#include<kmq.h>
+#include<khlist.h>
+#include<utils.h>
+#include<kherror.h>
+#include<khmsgtypes.h>
+#include<kconfig.h>
+#include<strsafe.h>
+
+#include<langres.h>
+
+#include "buf.h"
+#include "identity.h"
+#include "attrib.h"
+#include "type.h"
+#include "credential.h"
+#include "credset.h"
+#include "credtype.h"
+
+/* globals */
+
+extern HINSTANCE hinst_kcreddb;
+
+kconf_schema schema_kcdbconfig[];
+
+void kcdb_init(void);
+void kcdb_exit(void);
+khm_handle kcdb_get_config(void);
+
+#endif \ No newline at end of file
diff --git a/src/windows/identity/kcreddb/kcreddbmain.c b/src/windows/identity/kcreddb/kcreddbmain.c
new file mode 100644
index 0000000..796084a
--- /dev/null
+++ b/src/windows/identity/kcreddb/kcreddbmain.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+
+HINSTANCE hinst_kcreddb;
+
+void
+kcdb_process_attach(HINSTANCE hinstDLL) {
+ hinst_kcreddb = hinstDLL;
+ kcdb_init();
+}
+
+void
+kcdb_process_detach(void) {
+ kcdb_exit();
+}
diff --git a/src/windows/identity/kcreddb/lang/en_us/kcredres.rc b/src/windows/identity/kcreddb/lang/en_us/kcredres.rc
new file mode 100644
index 0000000..2f73319
--- /dev/null
+++ b/src/windows/identity/kcreddb/lang/en_us/kcredres.rc
@@ -0,0 +1,130 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\..\langres.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\..\\langres.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\..\\langres.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_CREDDB "Khimaira Credentials Database"
+ IDS_NAME "Name"
+ IDS_IDENTITY "Identity"
+ IDS_ISSUED "Issued on"
+ IDS_EXPIRES "Expires on"
+ IDS_TIMELEFT "Time left"
+ IDS_LOCATION "Location"
+ IDS_PARENT "Parent"
+ IDS_TYPE "Type"
+ IDS_IVL_EXPIRED "(Expired)"
+ IDS_IVL_D_H "%I64u days %I64u hours"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_IVL_H_M "%I64u hours %I64u mins"
+ IDS_IVL_M_S "%I64u mins %I64u secs"
+ IDS_IVL_S "%I64u seconds"
+ IDS_IVL_UNKNOWN "(Unknown)"
+ IDS_LIFETIME "Lifetime"
+ IDS_IVL_1D "1 day"
+ IDS_IVL_1H "1 hour"
+ IDS_IVL_1M "1 minute"
+ IDS_IVL_1S "1 second"
+ IDS_IVL_D "%I64u days"
+ IDS_IVL_H "%I64u hours"
+ IDS_IVL_M "%I64u minutes"
+ IDS_IVL_S_SPEC "s,sec,second,seconds,secs"
+ IDS_IVL_M_SPEC "m,min,mins,minutes"
+ IDS_IVL_H_SPEC "h,hrs,hours"
+ IDS_IVL_D_SPEC "d,day,days,ds"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_IVl_W_SPEC "w,wk,wks,weeks"
+ IDS_FLAGS "Flags"
+ IDS_RENEW_TIMELEFT "Renewable Time left"
+ IDS_RENEW_EXPIRES "Renewable time expires"
+ IDS_RENEW_LIFETIME "Renewable lifetime"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/windows/identity/kcreddb/langres.h b/src/windows/identity/kcreddb/langres.h
new file mode 100644
index 0000000..ab6620c
--- /dev/null
+++ b/src/windows/identity/kcreddb/langres.h
@@ -0,0 +1,49 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by D:\work\khimaira\src\kcreddb\lang\en_us\kcredres.rc
+//
+#define IDS_CREDDB 101
+#define IDS_NAME 102
+#define IDS_IDENTITY 103
+#define IDS_ISSUED 104
+#define IDS_EXPIRES 105
+#define IDS_TIMELEFT 106
+#define IDS_LOCATION 107
+#define IDS_PARENT 108
+#define IDS_TYPE 109
+#define IDS_IVL_EXPIRED 110
+#define IDS_IVL_D_H 111
+#define IDS_IVL_H_M 112
+#define IDS_IVL_M_S 113
+#define IDS_IVL_S 114
+#define IDS_IVL_UNKNOWN 115
+#define IDS_LIFETIME 116
+#define IDS_IVL_1D 117
+#define IDS_IVL_1H 118
+#define IDS_IVL_1M 119
+#define IDS_IVL_1S 120
+#define IDS_IVL_D 121
+#define IDS_IVL_H 122
+#define IDS_IVL_M 123
+#define IDS_IVL_S_SPEC 124
+#define IDS_IVL_M_SPEC 125
+#define IDS_IVL_H_SPEC 126
+#define IDS_IVL_D_SPEC 127
+#define IDS_IVl_W_SPEC 128
+#define IDS_IVL_W_SPEC 128
+#define IDS_IVl_W_SPEC 128
+#define IDS_FLAGS 129
+#define IDS_RENEW_TIMELEFT 130
+#define IDS_RENEW_EXPIRES 131
+#define IDS_RENEW_LIFETIME 132
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/windows/identity/kcreddb/resource.h b/src/windows/identity/kcreddb/resource.h
new file mode 100644
index 0000000..dfb47e0
--- /dev/null
+++ b/src/windows/identity/kcreddb/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by kcreddb.rc
+//
+#define IDS_PROJNAME 100
+#define IDR_WMDMLOGGER 101
+#define IDS_LOG_SEV_INFO 201
+#define IDS_LOG_SEV_WARN 202
+#define IDS_LOG_SEV_ERROR 203
+#define IDS_LOG_DATETIME 204
+#define IDS_LOG_SRCNAME 205
+#define IDS_DEF_LOGFILE 301
+#define IDS_DEF_MAXSIZE 302
+#define IDS_DEF_SHRINKTOSIZE 303
+#define IDS_DEF_LOGENABLED 304
+#define IDS_MUTEX_TIMEOUT 401
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 201
+#define _APS_NEXT_COMMAND_VALUE 32768
+#define _APS_NEXT_CONTROL_VALUE 201
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/windows/identity/kcreddb/type.c b/src/windows/identity/kcreddb/type.c
new file mode 100644
index 0000000..e416945
--- /dev/null
+++ b/src/windows/identity/kcreddb/type.c
@@ -0,0 +1,1295 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kcreddbinternal.h>
+#include<limits.h>
+
+CRITICAL_SECTION cs_type;
+hashtable * kcdb_type_namemap;
+kcdb_type_i ** kcdb_type_tbl;
+kcdb_type_i * kcdb_types = NULL;
+
+/* Void */
+
+#define GENERIC_VOID_STR L"(Void)"
+
+khm_int32 KHMAPI kcdb_type_void_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ size_t cbsize;
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+
+ cbsize = sizeof(GENERIC_VOID_STR);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cb_buf, GENERIC_VOID_STR);
+
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI kcdb_type_void_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ /* void is always valid, even if d is NULL */
+ return TRUE;
+}
+
+khm_int32 KHMAPI kcdb_type_void_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ /* voids can not be compared */
+ return 0;
+}
+
+khm_int32 KHMAPI kcdb_type_void_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ if(!cbd_dst)
+ return KHM_ERROR_INVALID_PARM;
+
+ *cbd_dst = 0;
+
+ /* copying a void doesn't do much */
+ return KHM_ERROR_SUCCESS;
+}
+
+
+/* String */
+khm_int32 KHMAPI kcdb_type_string_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ size_t cbsize;
+ wchar_t * sd;
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+
+ sd = (wchar_t *) d;
+
+ if(FAILED(StringCbLength(sd, KCDB_TYPE_MAXCB, &cbsize)))
+ return KHM_ERROR_INVALID_PARM;
+
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cb_buf, sd);
+
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI kcdb_type_string_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ size_t cbsize;
+
+ if(cbd == KCDB_CBSIZE_AUTO)
+ cbd = KCDB_TYPE_MAXCB;
+
+ if(FAILED(StringCbLength((wchar_t *) d, cbd, &cbsize)))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+khm_int32 KHMAPI kcdb_type_string_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ return wcscmp((const wchar_t *) d1, (const wchar_t *) d2);
+}
+
+khm_int32 KHMAPI kcdb_type_string_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ size_t cbsize;
+
+ if(!cbd_dst)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(cbd_src == KCDB_CBSIZE_AUTO) {
+ cbd_src = KCDB_TYPE_MAXCB;
+ }
+
+ if(FAILED(StringCbLength((const wchar_t *) d_src, cbd_src, &cbsize))) {
+ return KHM_ERROR_UNKNOWN;
+ }
+
+ cbsize += sizeof(wchar_t);
+
+ if(!d_dst || *cbd_dst < cbsize) {
+ *cbd_dst = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy((wchar_t *) d_dst, *cbd_dst, (const wchar_t *) d_src);
+ *cbd_dst = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+/* Date and time */
+
+
+khm_int32 KHMAPI kcdb_type_date_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ size_t cbsize;
+ size_t cchsize;
+ wchar_t * bufend;
+ SYSTEMTIME st_now;
+ SYSTEMTIME st_d;
+ SYSTEMTIME st_dl;
+ FILETIME *ft;
+ int today = 0;
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+
+ ft = (FILETIME *) d;
+
+ GetLocalTime(&st_now);
+ FileTimeToSystemTime(ft, &st_d);
+ SystemTimeToTzSpecificLocalTime(NULL, &st_d, &st_dl);
+ if(st_now.wYear == st_dl.wYear &&
+ st_now.wMonth == st_dl.wMonth &&
+ st_now.wDay == st_dl.wDay)
+ today = 1;
+
+ if(today && (flags & KCDB_TS_SHORT)) {
+ cbsize = 0;
+ } else {
+ cbsize = GetDateFormat(
+ LOCALE_USER_DEFAULT,
+ DATE_SHORTDATE,
+ &st_dl,
+ NULL,
+ NULL,
+ 0) * sizeof(wchar_t);
+ cbsize += sizeof(wchar_t);
+ }
+
+ cbsize += GetTimeFormat(
+ LOCALE_USER_DEFAULT,
+ 0,
+ &st_dl,
+ NULL,
+ NULL,
+ 0) * sizeof(wchar_t);
+
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ cchsize = cbsize / sizeof(wchar_t);
+
+ if(!today || !(flags & KCDB_TS_SHORT)) {
+ size_t cch_buf_len;
+
+ GetDateFormat(
+ LOCALE_USER_DEFAULT,
+ DATE_SHORTDATE,
+ &st_dl,
+ NULL,
+ buffer,
+ (int) cchsize);
+
+ StringCchCat(buffer, cchsize, L" ");
+
+ StringCchLength(buffer, cchsize, &cch_buf_len);
+
+ bufend = buffer + cch_buf_len;
+ cchsize -= cch_buf_len;
+ } else {
+ bufend = buffer;
+ }
+
+ GetTimeFormat(
+ LOCALE_USER_DEFAULT,
+ 0,
+ &st_dl,
+ NULL,
+ bufend,
+ (int) cchsize);
+
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI kcdb_type_date_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(FILETIME)));
+}
+
+khm_int32 KHMAPI kcdb_type_date_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ return (khm_int32) CompareFileTime((CONST FILETIME *) d1, (CONST FILETIME *) d2);
+}
+
+khm_int32 KHMAPI kcdb_type_date_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ if(d_dst && *cbd_dst >= sizeof(FILETIME)) {
+ *cbd_dst = sizeof(FILETIME);
+ *((FILETIME *) d_dst) = *((FILETIME *) d_src);
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *cbd_dst = sizeof(FILETIME);
+ return KHM_ERROR_TOO_LONG;
+ }
+}
+
+/* Interval */
+
+/* returns the number of milliseconds that must elapse away from the
+ interval specified in pft for the representation of pft to change
+ from whatever it is right now */
+KHMEXP long KHMAPI FtIntervalMsToRepChange(LPFILETIME pft)
+{
+ __int64 ms,s,m,h,d;
+ long l;
+
+ ms = *((__int64 *) pft) / 10000i64;
+
+ if(ms < 0 || *((__int64 *) pft) == _I64_MAX)
+ return -1;
+
+ s = ms / 1000i64;
+ m = s / 60;
+ h = s / 3600;
+ d = s / (3600*24);
+
+ if(d > 0) {
+ /* rep change at next hour change */
+ l = (long) (ms % (3600*1000i64));
+ } else if(h > 0) {
+ /* rep change at next minute change */
+ l = (long) (ms % (60*1000i64));
+ } else {
+ l = (long) (ms % 1000);
+ }
+
+ return l;
+}
+
+KHMEXP khm_int32 KHMAPI FtIntervalToString(LPFILETIME data, wchar_t * buffer, khm_size * cb_buf)
+{
+ size_t cbsize;
+ __int64 s,m,h,d;
+ wchar_t ibuf[256];
+ wchar_t fbuf[256];
+ wchar_t * t;
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+ s = *((__int64 *) data) / 10000000i64;
+
+ m = s / 60;
+ h = s / 3600;
+ d = s / (3600*24);
+
+ if(*((__int64 *) data) == _I64_MAX) {
+ LoadString(hinst_kcreddb, IDS_IVL_UNKNOWN, ibuf, sizeof(ibuf)/sizeof(wchar_t));
+ } else if(s < 0) {
+ LoadString(hinst_kcreddb, IDS_IVL_EXPIRED, ibuf, sizeof(ibuf)/sizeof(wchar_t));
+ } else if(d > 0) {
+ h = (s - (d * 3600 * 24)) / 3600;
+ if(d == 1) {
+ LoadString(hinst_kcreddb, IDS_IVL_1D, ibuf, ARRAYLENGTH(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_D, fbuf, ARRAYLENGTH(fbuf));
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, d);
+ }
+ if(h > 0) {
+ StringCbCat(ibuf, sizeof(ibuf), L" ");
+ t = ibuf + wcslen(ibuf);
+ if(h == 1)
+ {
+ LoadString(hinst_kcreddb, IDS_IVL_1H, t, ARRAYLENGTH(ibuf) - wcslen(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf));
+ StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, h);
+ }
+ }
+ } else if(h > 0) {
+ m = (s - (h * 3600)) / 60;
+ if(h == 1) {
+ LoadString(hinst_kcreddb, IDS_IVL_1H, ibuf, ARRAYLENGTH(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf));
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, h);
+ }
+ if(m > 0) {
+ StringCbCat(ibuf, sizeof(ibuf), L" ");
+ t = ibuf + wcslen(ibuf);
+ if(m == 1)
+ {
+ LoadString(hinst_kcreddb, IDS_IVL_1M, t, ARRAYLENGTH(ibuf) - wcslen(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf));
+ StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, m);
+ }
+ }
+ } else if(m > 0) {
+ s -= m * 60;
+ if(m == 1) {
+ LoadString(hinst_kcreddb, IDS_IVL_1M, ibuf, ARRAYLENGTH(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf));
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, m);
+ }
+ if(s > 0) {
+ StringCbCat(ibuf, sizeof(ibuf), L" ");
+ t = ibuf + wcslen(ibuf);
+ if(s == 1)
+ {
+ LoadString(hinst_kcreddb, IDS_IVL_1S, t, ARRAYLENGTH(ibuf) - wcslen(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, ARRAYLENGTH(fbuf));
+ StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, s);
+ }
+ }
+ } else {
+ if(s == 1) {
+ LoadString(hinst_kcreddb, IDS_IVL_1S, ibuf, ARRAYLENGTH(ibuf));
+ } else {
+ LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, sizeof(fbuf)/sizeof(wchar_t));
+ StringCbPrintf(ibuf, sizeof(ibuf), fbuf, s);
+ }
+ }
+
+ StringCbLength(ibuf, sizeof(ibuf), &cbsize);
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cb_buf, ibuf);
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_int32 KHMAPI kcdb_type_interval_toString(
+ const void * data,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ return FtIntervalToString((LPFILETIME) data, buffer, cb_buf);
+}
+
+khm_boolean KHMAPI kcdb_type_interval_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ return (d && (cbd == sizeof(FILETIME) || cbd == KCDB_CBSIZE_AUTO));
+}
+
+khm_int32 KHMAPI kcdb_type_interval_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ __int64 i1, i2;
+
+ i1 = *((__int64 *) d1);
+ i2 = *((__int64 *) d2);
+
+ if(i1 < i2)
+ return -1;
+ else if(i1 > i2)
+ return 1;
+ else
+ return 0;
+}
+
+khm_int32 KHMAPI kcdb_type_interval_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ if(d_dst && *cbd_dst >= sizeof(__int64)) {
+ *cbd_dst = sizeof(__int64);
+ *((__int64 *) d_dst) = *((__int64 *) d_src);
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *cbd_dst = sizeof(__int64);
+ return KHM_ERROR_TOO_LONG;
+ }
+}
+
+/* Int32 */
+
+khm_int32 KHMAPI kcdb_type_int32_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ size_t cbsize;
+ wchar_t ibuf[12];
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+
+ StringCbPrintf(ibuf, sizeof(ibuf), L"%d", *((khm_int32 *) d));
+ StringCbLength(ibuf, sizeof(ibuf), &cbsize);
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf);
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI kcdb_type_int32_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(khm_int32)));
+}
+
+khm_int32 KHMAPI kcdb_type_int32_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ return *((khm_int32 *) d1) - *((khm_int32 *) d2);
+}
+
+khm_int32 KHMAPI kcdb_type_int32_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ if(d_dst && (*cbd_dst >= sizeof(khm_int32))) {
+ *cbd_dst = sizeof(khm_int32);
+ *((khm_int32 *) d_dst) = *((khm_int32 *) d_src);
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *cbd_dst = sizeof(khm_int32);
+ return KHM_ERROR_TOO_LONG;
+ }
+}
+
+/* Int64 */
+
+khm_int32 KHMAPI kcdb_type_int64_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ size_t cbsize;
+ wchar_t ibuf[22];
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+
+ StringCbPrintf(ibuf, sizeof(ibuf), L"%I64d", *((__int64 *) d));
+ StringCbLength(ibuf, sizeof(ibuf), &cbsize);
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf);
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI kcdb_type_int64_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(__int64)));
+}
+
+khm_int32 KHMAPI kcdb_type_int64_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ __int64 r = *((__int64 *) d1) - *((__int64 *) d2);
+ return (r==0i64)?0:((r>0i64)?1:-1);
+}
+
+khm_int32 KHMAPI kcdb_type_int64_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ if(d_dst && (*cbd_dst >= sizeof(__int64))) {
+ *cbd_dst = sizeof(__int64);
+ *((__int64 *) d_dst) = *((__int64 *) d_src);
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *cbd_dst = sizeof(__int64);
+ return KHM_ERROR_TOO_LONG;
+ }
+}
+
+/* Data */
+#define GENERIC_DATA_STR L"(Data)"
+
+khm_int32 KHMAPI kcdb_type_data_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags)
+{
+ size_t cbsize;
+
+ if(!cb_buf)
+ return KHM_ERROR_INVALID_PARM;
+
+ cbsize = sizeof(GENERIC_DATA_STR);
+
+ if(!buffer || *cb_buf < cbsize) {
+ *cb_buf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cb_buf, GENERIC_DATA_STR);
+
+ *cb_buf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_boolean KHMAPI kcdb_type_data_isValid(
+ const void * d,
+ khm_size cbd)
+{
+ /* data is always valid, even if d is NULL */
+ return TRUE;
+}
+
+khm_int32 KHMAPI kcdb_type_data_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2)
+{
+ /* datas can not be compared */
+ return 0;
+}
+
+khm_int32 KHMAPI kcdb_type_data_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst)
+{
+ if(!cbd_dst)
+ return KHM_ERROR_INVALID_PARM;
+
+ *cbd_dst = cbd_src;
+
+ if(!d_dst || *cbd_dst < cbd_src) {
+ return KHM_ERROR_TOO_LONG;
+ } else {
+ memcpy(d_dst, d_src, cbd_src);
+ return KHM_ERROR_SUCCESS;
+ }
+}
+
+
+void kcdb_type_msg_completion(kmq_message * m)
+{
+ kcdb_type_release((kcdb_type_i *) m->vparam);
+}
+
+void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t)
+{
+ kcdb_type_hold(t);
+ kmq_post_message(KMSG_KCDB, KMSG_KCDB_TYPE, op, (void *) t);
+}
+
+void kcdb_type_init(void)
+{
+ kcdb_type type;
+
+ InitializeCriticalSection(&cs_type);
+ kcdb_type_namemap = hash_new_hashtable(
+ KCDB_TYPE_HASH_SIZE,
+ hash_string,
+ hash_string_comp,
+ kcdb_type_add_ref,
+ kcdb_type_del_ref);
+ kcdb_type_tbl = malloc(sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1));
+ ZeroMemory(kcdb_type_tbl, sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1));
+ kcdb_types = NULL;
+
+ /*TODO: register standard data types */
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_void_comp;
+ type.dup = kcdb_type_void_dup;
+ type.isValid = kcdb_type_void_isValid;
+ type.toString = kcdb_type_void_toString;
+ type.name = KCDB_TYPENAME_VOID;
+ type.id = KCDB_TYPE_VOID;
+
+ kcdb_type_register(&type, NULL);
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_string_comp;
+ type.dup = kcdb_type_string_dup;
+ type.isValid = kcdb_type_string_isValid;
+ type.toString = kcdb_type_string_toString;
+ type.name = KCDB_TYPENAME_STRING;
+ type.id = KCDB_TYPE_STRING;
+ type.flags = KCDB_TYPE_FLAG_CB_AUTO;
+
+ kcdb_type_register(&type, NULL);
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_date_comp;
+ type.dup = kcdb_type_date_dup;
+ type.isValid = kcdb_type_date_isValid;
+ type.toString = kcdb_type_date_toString;
+ type.name = KCDB_TYPENAME_DATE;
+ type.id = KCDB_TYPE_DATE;
+ type.cb_max = sizeof(FILETIME);
+ type.cb_min = sizeof(FILETIME);
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;
+
+ kcdb_type_register(&type, NULL);
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_interval_comp;
+ type.dup = kcdb_type_interval_dup;
+ type.isValid = kcdb_type_interval_isValid;
+ type.toString = kcdb_type_interval_toString;
+ type.name = KCDB_TYPENAME_INTERVAL;
+ type.id = KCDB_TYPE_INTERVAL;
+ type.cb_max = sizeof(__int64);
+ type.cb_min = sizeof(__int64);
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;
+
+ kcdb_type_register(&type, NULL);
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_int32_comp;
+ type.dup = kcdb_type_int32_dup;
+ type.isValid = kcdb_type_int32_isValid;
+ type.toString = kcdb_type_int32_toString;
+ type.name = KCDB_TYPENAME_INT32;
+ type.id = KCDB_TYPE_INT32;
+ type.cb_max = sizeof(khm_int32);
+ type.cb_min = sizeof(khm_int32);
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;
+
+ kcdb_type_register(&type, NULL);
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_int64_comp;
+ type.dup = kcdb_type_int64_dup;
+ type.isValid = kcdb_type_int64_isValid;
+ type.toString = kcdb_type_int64_toString;
+ type.name = KCDB_TYPENAME_INT64;
+ type.id = KCDB_TYPE_INT64;
+ type.cb_max = sizeof(__int64);
+ type.cb_min = sizeof(__int64);
+ type.flags = KCDB_TYPE_FLAG_CB_FIXED;
+
+ kcdb_type_register(&type, NULL);
+
+ ZeroMemory(&type, sizeof(type));
+ type.comp = kcdb_type_data_comp;
+ type.dup = kcdb_type_data_dup;
+ type.isValid = kcdb_type_data_isValid;
+ type.toString = kcdb_type_data_toString;
+ type.name = KCDB_TYPENAME_DATA;
+ type.id = KCDB_TYPE_DATA;
+
+ kcdb_type_register(&type, NULL);
+}
+
+void kcdb_type_add_ref(const void *key, void *vt)
+{
+ kcdb_type_hold((kcdb_type_i *) vt);
+}
+
+void kcdb_type_del_ref(const void *key, void *vt)
+{
+ kcdb_type_release((kcdb_type_i *) vt);
+}
+
+khm_int32 kcdb_type_hold(kcdb_type_i * t)
+{
+ if(!t)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_type);
+ t->refcount++;
+ LeaveCriticalSection(&cs_type);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+khm_int32 kcdb_type_release(kcdb_type_i * t)
+{
+ if(!t)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_type);
+ t->refcount--;
+ kcdb_type_check_and_delete(t->type.id);
+ LeaveCriticalSection(&cs_type);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+void kcdb_type_exit(void)
+{
+ EnterCriticalSection(&cs_type);
+ free(kcdb_type_tbl);
+ /*TODO: free up the individual types */
+ LeaveCriticalSection(&cs_type);
+ DeleteCriticalSection(&cs_type);
+}
+
+void kcdb_type_check_and_delete(khm_int32 id)
+{
+ kcdb_type_i * t;
+
+ if(id < 0 || id > KCDB_TYPE_MAX_ID)
+ return;
+
+ EnterCriticalSection(&cs_type);
+ t = kcdb_type_tbl[id];
+ if(t && !t->refcount) {
+ kcdb_type_tbl[id] = NULL;
+ LDELETE(&kcdb_types, t);
+ /* must already be out of the hash-table, otherwise refcount should not
+ be zero */
+ free(t->type.name);
+ free(t);
+ }
+ LeaveCriticalSection(&cs_type);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_get_id(wchar_t *name, khm_int32 * id)
+{
+ kcdb_type_i * t;
+ size_t cbsize;
+
+ if(FAILED(StringCbLength(name, KCDB_MAXCB_NAME, &cbsize))) {
+ /* also fails of name is NULL */
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ EnterCriticalSection(&cs_type);
+ t = hash_lookup(kcdb_type_namemap, (void*) name);
+ LeaveCriticalSection(&cs_type);
+
+ if(!t) {
+ *id = KCDB_TYPE_INVALID;
+ return KHM_ERROR_NOT_FOUND;
+ } else {
+ *id = t->type.id;
+ return KHM_ERROR_SUCCESS;
+ }
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_get_info(khm_int32 id, kcdb_type ** info)
+{
+ kcdb_type_i * t;
+
+ if(id < 0 || id > KCDB_TYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_type);
+ t = kcdb_type_tbl[id];
+
+ if (t)
+ kcdb_type_hold(t);
+ LeaveCriticalSection(&cs_type);
+
+ if(info)
+ *info = (kcdb_type *) t;
+ else if (t)
+ kcdb_type_release(t);
+
+ return (t)? KHM_ERROR_SUCCESS : KHM_ERROR_NOT_FOUND;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_release_info(kcdb_type * info)
+{
+ return kcdb_type_release((kcdb_type_i *) info);
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_get_name(khm_int32 id, wchar_t * buffer, khm_size * cbbuf)
+{
+ size_t cbsize;
+ kcdb_type_i * t;
+
+ if(id < 0 || id > KCDB_TYPE_MAX_ID || !cbbuf)
+ return KHM_ERROR_INVALID_PARM;
+
+ t = kcdb_type_tbl[id];
+
+ if(!t)
+ return KHM_ERROR_NOT_FOUND;
+
+ if(FAILED(StringCbLength(t->type.name, KCDB_MAXCB_NAME, &cbsize)))
+ return KHM_ERROR_UNKNOWN;
+
+ cbsize += sizeof(wchar_t);
+
+ if(!buffer || *cbbuf < cbsize) {
+ *cbbuf = cbsize;
+ return KHM_ERROR_TOO_LONG;
+ }
+
+ StringCbCopy(buffer, *cbbuf, t->type.name);
+ *cbbuf = cbsize;
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_register(kcdb_type * type, khm_int32 * new_id)
+{
+ kcdb_type_i *t;
+ size_t cbsize;
+ khm_int32 type_id;
+
+ if(!type ||
+ !type->comp ||
+ !type->dup ||
+ !type->isValid ||
+ !type->toString ||
+ !type->name)
+ return KHM_ERROR_INVALID_PARM;
+
+ if((type->flags & KCDB_TYPE_FLAG_CB_MIN) &&
+ (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB))
+ {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if((type->flags & KCDB_TYPE_FLAG_CB_MAX) &&
+ (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB))
+ {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if((type->flags & KCDB_TYPE_FLAG_CB_MIN) &&
+ (type->flags & KCDB_TYPE_FLAG_CB_MAX) &&
+ (type->cb_max < type->cb_min))
+ {
+ return KHM_ERROR_INVALID_PARM;
+ }
+
+ if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cbsize)))
+ return KHM_ERROR_TOO_LONG;
+
+ cbsize += sizeof(wchar_t);
+
+ EnterCriticalSection(&cs_type);
+ if(type->id == KCDB_TYPE_INVALID) {
+ kcdb_type_get_next_free(&type_id);
+ } else if(type->id < 0 || type->id > KCDB_TYPE_MAX_ID) {
+ LeaveCriticalSection(&cs_type);
+ return KHM_ERROR_INVALID_PARM;
+ } else if(kcdb_type_tbl[type->id]) {
+ LeaveCriticalSection(&cs_type);
+ return KHM_ERROR_DUPLICATE;
+ } else {
+ type_id = type->id;
+ }
+
+ if(type_id == KCDB_TYPE_INVALID) {
+ LeaveCriticalSection(&cs_type);
+ return KHM_ERROR_NO_RESOURCES;
+ }
+
+ t = malloc(sizeof(kcdb_type_i));
+ ZeroMemory(t, sizeof(kcdb_type_i));
+
+ t->type.name = malloc(cbsize);
+ StringCbCopy(t->type.name, cbsize, type->name);
+
+ t->type.comp = type->comp;
+ t->type.dup = type->dup;
+ t->type.flags = type->flags;
+ t->type.id = type_id;
+ t->type.isValid = type->isValid;
+ t->type.toString = type->toString;
+
+ LINIT(t);
+
+ kcdb_type_tbl[type_id] = t;
+ LPUSH(&kcdb_types, t);
+
+ hash_add(kcdb_type_namemap, (void *) t->type.name, (void *) t);
+
+ LeaveCriticalSection(&cs_type);
+
+ if(new_id)
+ *new_id = type_id;
+
+ kcdb_type_post_message(KCDB_OP_INSERT, t);
+
+ return KHM_ERROR_SUCCESS;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_unregister(khm_int32 id)
+{
+ kcdb_type_i * t;
+
+ if(id < 0 || id > KCDB_TYPE_MAX_ID)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_type);
+ t = kcdb_type_tbl[id];
+ if(t) {
+ kcdb_type_post_message(KCDB_OP_DELETE, t);
+ /* we are going to remove t from the hash table. If no one is holding
+ a reference to it, then we can free it (actually, the del_ref code
+ will take care of that anyway). If there is a hold, then it will
+ get freed when they release it.
+
+ Actually, the post_message call above pretty much guarantees that
+ the type has a hold on it.*/
+ t->type.flags |= KCDB_TYPE_FLAG_DELETED;
+ hash_del(kcdb_type_namemap, t->type.name);
+ }
+ LeaveCriticalSection(&cs_type);
+
+ if(t)
+ return KHM_ERROR_SUCCESS;
+ else
+ return KHM_ERROR_NOT_FOUND;
+}
+
+KHMEXP khm_int32 KHMAPI kcdb_type_get_next_free(khm_int32 * id)
+{
+ int i;
+
+ if(!id)
+ return KHM_ERROR_INVALID_PARM;
+
+ /* do a linear search because this function only gets called a few times */
+ EnterCriticalSection(&cs_type);
+ for(i=0; i <= KCDB_TYPE_MAX_ID; i++) {
+ if(!kcdb_type_tbl[i])
+ break;
+ }
+ LeaveCriticalSection(&cs_type);
+
+ if(i <= KCDB_TYPE_MAX_ID) {
+ *id = i;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *id = KCDB_TYPE_INVALID;
+ return KHM_ERROR_NO_RESOURCES;
+ }
+}
+
+/* Conversion functions */
+
+KHMEXP void KHMAPI TimetToFileTime( time_t t, LPFILETIME pft )
+{
+ LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000i64;
+ pft->dwLowDateTime = (DWORD) ll;
+ pft->dwHighDateTime = (DWORD) (ll >> 32);
+}
+
+KHMEXP void KHMAPI TimetToFileTimeInterval(time_t t, LPFILETIME pft)
+{
+ LONGLONG ll = Int32x32To64(t, 10000000);
+ pft->dwLowDateTime = (DWORD) ll;
+ pft->dwHighDateTime = (DWORD) (ll >> 32);
+}
+
+KHMEXP long KHMAPI FtIntervalToSeconds(LPFILETIME pft)
+{
+ __int64 i = *((__int64 *) pft);
+ return (long) (i / 10000000i64);
+}
+
+KHMEXP long KHMAPI FtIntervalToMilliseconds(LPFILETIME pft)
+{
+ __int64 i = *((__int64 *) pft);
+ return (long) (i / 10000i64);
+}
+
+KHMEXP long KHMAPI FtCompare(LPFILETIME pft1, LPFILETIME pft2) {
+ __int64 i1 = *((__int64 *) pft1);
+ __int64 i2 = *((__int64 *) pft2);
+
+ if (i1 < i2)
+ return -1;
+ if (i1 == i2)
+ return 0;
+ return 1;
+}
+
+KHMEXP int KHMAPI AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr)
+{
+ size_t nc;
+
+ if(cbwstr == 0)
+ return 0;
+
+ nc = strlen(astr);
+ if(nc == MultiByteToWideChar(
+ CP_ACP,
+ 0,
+ astr,
+ (int) nc,
+ wstr,
+ (int)(cbwstr / sizeof(wchar_t) - 1))) {
+ wstr[nc] = L'\0';
+ } else {
+ wstr[0] = L'\0';
+ nc = 0;
+ }
+
+ return (int) nc;
+}
+
+KHMEXP int KHMAPI UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src)
+{
+ size_t nc;
+
+ if(cbdest == 0)
+ return 0;
+
+ dest[0] = 0;
+
+ if(FAILED(StringCchLength(src, cbdest, &nc)) || nc*sizeof(char) >= cbdest)
+ // note that cbdest counts the terminating NULL, while nc doesn't
+ return 0;
+
+ nc = WideCharToMultiByte(
+ CP_ACP,
+ WC_NO_BEST_FIT_CHARS,
+ src,
+ (int) nc,
+ dest,
+ (int) cbdest,
+ NULL,
+ NULL);
+
+ dest[nc] = 0;
+
+ return (int) nc;
+}
+
+#define MAX_IVL_SPECLIST_LEN 256
+#define MAX_IVL_UNITS 5
+
+enum _ivl_indices {
+ IVL_SECONDS = 0,
+ IVL_MINUTES,
+ IVL_HOURS,
+ IVL_DAYS,
+ IVL_WEEKS
+};
+
+typedef struct ivspec_t {
+ wchar_t str[MAX_IVL_SPECLIST_LEN];
+ __int64 mul;
+} ivspec;
+
+static ivspec ivspecs[MAX_IVL_UNITS];
+static BOOL ivspecs_loaded = FALSE;
+
+int _iv_is_in_spec(wchar_t *s, int n, wchar_t * spec)
+{
+ /* spec strigns are comma separated */
+ wchar_t *b, *e;
+
+ b = spec;
+ while(*b) {
+ e = wcschr(b, L',');
+ if(!e)
+ e = b + wcslen(b);
+
+ if((e - b) == n && !wcsnicmp(b, s, n)) {
+ return TRUE;
+ }
+
+ if(*e)
+ b = e+1;
+ else
+ break;
+ }
+
+ return FALSE;
+}
+
+KHMEXP khm_int32 KHMAPI IntervalStringToFt(FILETIME * pft, wchar_t * str)
+{
+ size_t cb;
+ wchar_t * b;
+ __int64 *pr, t;
+
+ pr = (__int64 *) pft;
+ *pr = 0;
+
+ /* ideally we should synchronize this, but it doesn't hurt if two
+ threads do this at the same time, because we only set the ivspecs_loaded
+ flag when we are done */
+ if(!ivspecs_loaded) {
+ LoadString(hinst_kcreddb, IDS_IVL_S_SPEC, ivspecs[IVL_SECONDS].str, MAX_IVL_SPECLIST_LEN);
+ ivspecs[IVL_SECONDS].mul = 10000000i64;
+ LoadString(hinst_kcreddb, IDS_IVL_M_SPEC, ivspecs[IVL_MINUTES].str, MAX_IVL_SPECLIST_LEN);
+ ivspecs[IVL_MINUTES].mul = ivspecs[IVL_SECONDS].mul * 60;
+ LoadString(hinst_kcreddb, IDS_IVL_H_SPEC, ivspecs[2].str, MAX_IVL_SPECLIST_LEN);
+ ivspecs[IVL_HOURS].mul = ivspecs[IVL_MINUTES].mul * 60;
+ LoadString(hinst_kcreddb, IDS_IVL_D_SPEC, ivspecs[3].str, MAX_IVL_SPECLIST_LEN);
+ ivspecs[IVL_DAYS].mul = ivspecs[IVL_HOURS].mul * 24;
+ LoadString(hinst_kcreddb, IDS_IVL_W_SPEC, ivspecs[4].str, MAX_IVL_SPECLIST_LEN);
+ ivspecs[IVL_WEEKS].mul = ivspecs[IVL_DAYS].mul * 7;
+
+ ivspecs_loaded = TRUE;
+ }
+
+ if(!str || FAILED(StringCbLength(str, MAX_IVL_SPECLIST_LEN, &cb)))
+ return KHM_ERROR_INVALID_PARM;
+
+ b = str;
+ t = 0;
+ while(*b) {
+ __int64 f = 1;
+ wchar_t *e;
+ int i;
+
+ while(*b && iswspace(*b))
+ b++;
+
+ if(*b && iswdigit(*b)) {
+ f = _wtoi64(b);
+
+ while(*b && iswdigit(*b))
+ b++;
+ }
+
+ while(*b && iswspace(*b))
+ b++;
+
+ if(!*b) /* no unit specified */
+ return KHM_ERROR_INVALID_PARM;
+
+ e = b;
+
+ while(*e && !iswspace(*e))
+ e++;
+
+ for(i=0; i < MAX_IVL_UNITS; i++) {
+ if(_iv_is_in_spec(b, (int)(e-b), ivspecs[i].str))
+ break;
+ }
+
+ if(i==MAX_IVL_UNITS)
+ return KHM_ERROR_INVALID_PARM;
+
+ t += f * ivspecs[i].mul;
+
+ b = e;
+ }
+
+ *pr = t;
+
+ return KHM_ERROR_SUCCESS;
+}
diff --git a/src/windows/identity/kcreddb/type.h b/src/windows/identity/kcreddb/type.h
new file mode 100644
index 0000000..9d8b52e
--- /dev/null
+++ b/src/windows/identity/kcreddb/type.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#ifndef __KHIMAIRA_KCDB_TYPE_H
+#define __KHIMAIRA_KCDB_TYPE_H
+
+/* Types */
+
+typedef struct kcdb_type_i_t {
+ kcdb_type type;
+
+ khm_int32 refcount;
+
+ struct kcdb_type_i_t * next;
+ struct kcdb_type_i_t * prev;
+} kcdb_type_i;
+
+#define KCDB_TYPE_HASH_SIZE 31
+
+#define KCDB_TYPE_FLAG_DELETED 8
+
+void kcdb_type_init(void);
+void kcdb_type_exit(void);
+void kcdb_type_add_ref(const void *key, void *vt);
+void kcdb_type_del_ref(const void *key, void *vt);
+void kcdb_type_msg_completion(kmq_message * m);
+khm_int32 kcdb_type_hold(kcdb_type_i * t);
+khm_int32 kcdb_type_release(kcdb_type_i * t);
+void kcdb_type_check_and_delete(khm_int32 id);
+void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t);
+
+khm_int32 KHMAPI kcdb_type_void_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_void_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_void_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_void_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+khm_int32 KHMAPI kcdb_type_string_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_string_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_string_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_string_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+khm_int32 KHMAPI kcdb_type_date_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_date_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_date_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_date_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+khm_int32 KHMAPI kcdb_type_interval_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_interval_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_interval_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_interval_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+khm_int32 KHMAPI kcdb_type_int32_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_int32_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_int32_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_int32_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+khm_int32 KHMAPI kcdb_type_int64_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_int64_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_int64_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_int64_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+khm_int32 KHMAPI kcdb_type_data_toString(
+ const void * d,
+ khm_size cbd,
+ wchar_t * buffer,
+ khm_size * cb_buf,
+ khm_int32 flags);
+
+khm_boolean KHMAPI kcdb_type_data_isValid(
+ const void * d,
+ khm_size cbd);
+
+khm_int32 KHMAPI kcdb_type_data_comp(
+ const void * d1,
+ khm_size cbd1,
+ const void * d2,
+ khm_size cbd2);
+
+khm_int32 KHMAPI kcdb_type_data_dup(
+ const void * d_src,
+ khm_size cbd_src,
+ void * d_dst,
+ khm_size * cbd_dst);
+
+#endif \ No newline at end of file