Source files containing common routines used by both
authorJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 22 May 2006 17:12:49 +0000 (17:12 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 22 May 2006 17:12:49 +0000 (17:12 +0000)
the client and the server.

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/ccapi@18027 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/ccapi/common/NTMakefile [new file with mode: 0644]
src/lib/ccapi/common/generic_lists.c [new file with mode: 0644]
src/lib/ccapi/common/marshall.c [new file with mode: 0644]
src/lib/ccapi/common/msg.c [new file with mode: 0644]

diff --git a/src/lib/ccapi/common/NTMakefile b/src/lib/ccapi/common/NTMakefile
new file mode 100644 (file)
index 0000000..d0d92fc
--- /dev/null
@@ -0,0 +1,15 @@
+!INCLUDE <WIN32.MAK>\r
+\r
+CFLAGS = -I../include $(cdebug) $(cflags) $(cvarsdll)\r
+\r
+CC_COMMON_OBJS = marshall.obj msg.obj generic_lists.obj\r
+\r
+CC_COMMON_LIB = cc_common.lib\r
+\r
+$(CC_COMMON_LIB): $(CC_COMMON_OBJS)\r
+        $(implib) /NOLOGO /OUT:$@ $**\r
+\r
+all: $(CC_COMMON_LIB)\r
+\r
+clean:\r
+        del *.obj *.lib\r
diff --git a/src/lib/ccapi/common/generic_lists.c b/src/lib/ccapi/common/generic_lists.c
new file mode 100644 (file)
index 0000000..a48c528
--- /dev/null
@@ -0,0 +1,402 @@
+/* $Copyright:\r
+*\r
+* Copyright 2004-2006 by the Massachusetts Institute of Technology.\r
+* \r
+* All rights reserved.\r
+* \r
+* Export of this software from the United States of America may require a\r
+* specific license from the United States Government.  It is the\r
+* responsibility of any person or organization contemplating export to\r
+* obtain such a license before exporting.\r
+* \r
+* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute\r
+* this software and its documentation for any purpose and without fee is\r
+* hereby granted, provided that the above copyright notice appear in all\r
+* copies and that both that copyright notice and this permission notice\r
+* appear in supporting documentation, and that the name of M.I.T. not be\r
+* used in advertising or publicity pertaining to distribution of the\r
+* software without specific, written prior permission.  Furthermore if you\r
+* modify this software you must label your software as modified software\r
+* and not distribute it in such a fashion that it might be confused with\r
+* the original MIT software. M.I.T. makes no representations about the\r
+* suitability of this software for any purpose.  It is provided "as is"\r
+* without express or implied warranty.\r
+* \r
+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED\r
+* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF\r
+* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+* \r
+* Individual source code files are copyright MIT, Cygnus Support,\r
+* OpenVision, Oracle, Sun Soft, FundsXpress, and others.\r
+* \r
+* Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,\r
+* and Zephyr are trademarks of the Massachusetts Institute of Technology\r
+* (MIT).  No commercial use of these trademarks may be made without prior\r
+* written permission of MIT.\r
+* \r
+* "Commercial use" means use of a name in a product or other for-profit\r
+* manner.  It does NOT prevent a commercial firm from referring to the MIT\r
+* trademarks in order to convey information (although in doing so,\r
+* recognition of their trademark status should be given).\r
+* $\r
+*/\r
+\r
+\r
+/*\r
+ * Lists implementation.\r
+ * \r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <memory.h>\r
+\r
+#include "CredentialsCache.h"\r
+#include "generic_lists.h"\r
+\r
+/* this is an incomplete enumeration just including the generic type */\r
+enum cc_list_type {\r
+    generic = 0\r
+};\r
+\r
+/**\r
+ * cci_generic_iterate_has_next()\r
+ *\r
+ * Purpose: Determine if an iterator has a next element\r
+ *\r
+ * Return:  1 if another element exists\r
+ *          0 if no additional elements exist\r
+ *\r
+ * Errors:  None\r
+ *\r
+ */\r
+cc_int32 \r
+cci_generic_iterate_has_next(cc_generic_iterate_t *iterate) \r
+{\r
+    return ((iterate == NULL || iterate->next == NULL) ? 0 : 1);\r
+}\r
+\r
+/**\r
+ * cci_generic_iterate_next()\r
+ *\r
+ * Purpose: Retrieve the next element from an iterator and advance\r
+ *          the iterator\r
+ *\r
+ * Return:  non-NULL, the next element in the iterator\r
+ *          NULL, the iterator list is empty or iterator is invalid\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_iterate_next(cc_generic_iterate_t *iterator, cc_generic_list_node_t** nodepp) \r
+{\r
+    cc_generic_list_node_t* ret;\r
+    \r
+    if (iterator == NULL || nodepp == NULL)\r
+        return ccErrBadParam;\r
+\r
+    ret = iterator->next;\r
+    if (iterator->next != NULL)\r
+        iterator->next = iterator->next->next;\r
+\r
+    *nodepp = ret;\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_list_new()\r
+ *\r
+ * Purpose: Allocate new generic list\r
+ *\r
+ * Return:  non-NULL, an empty list\r
+ *          NULL, failure\r
+ *\r
+ * Errors:  ccErrNoMem\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_list_new(cc_generic_list_head_t ** listpp) \r
+{\r
+    cc_generic_list_head_t* ret = (cc_generic_list_head_t *)malloc(sizeof(cc_generic_list_head_t));\r
+    if (ret == NULL)\r
+        return ccErrNoMem;\r
+       \r
+    ret->type = generic;\r
+    ret->head = ret->tail = NULL;\r
+    *listpp = ret;\r
+\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_list_append()\r
+ *\r
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data' \r
+ *\r
+ * Return:  non-NULL, a pointer to the newly allocated node\r
+ *          NULL, failure\r
+ *\r
+ * Errors:  ccErrNoMem,ccErrBadParam\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_list_append(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t** nodepp) \r
+{\r
+    cc_generic_list_node_t* new_node;\r
+\r
+    if ( data == NULL || len == 0 )\r
+        return ccErrBadParam;\r
+\r
+    new_node = (cc_generic_list_node_t *)malloc(sizeof(cc_generic_list_node_t));\r
+    if (new_node == NULL)\r
+        return ccErrNoMem;\r
+\r
+    new_node->data = malloc(len);\r
+    if ( new_node->data == NULL ) {\r
+        free(new_node);\r
+        return ccErrNoMem;         \r
+    }\r
+    \r
+    memcpy(new_node->data,data,len);\r
+    new_node->len = len;\r
+\r
+    if (head->head == NULL) { /*empty list*/\r
+        head->head = new_node;\r
+        head->tail = new_node;\r
+           new_node->next = new_node->prev = NULL;\r
+    } else {\r
+        new_node->prev = head->tail;\r
+        head->tail->next = new_node;\r
+        head->tail = new_node;\r
+               new_node->next = NULL;\r
+    }\r
+       if (nodepp != NULL)\r
+           *nodepp = new_node;\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_list_prepend()\r
+ *\r
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data'\r
+ *\r
+ * Return:  non-NULL, a pointer to the newly allocated node\r
+ *          NULL, failure\r
+ *\r
+ * Errors:  ccErrNoMem, ccErrBadParam\r
+ *\r
+ */\r
+cc_int32 \r
+cci_generic_list_prepend(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t** nodepp) \r
+{\r
+    cc_generic_list_node_t* new_node;\r
+\r
+    if ( data == NULL || len == 0 )\r
+        return ccErrBadParam;\r
+\r
+    new_node = (cc_generic_list_node_t *)malloc(sizeof(cc_generic_list_node_t));\r
+    if (new_node == NULL)\r
+        return ccErrNoMem;\r
+\r
+    new_node->data = malloc(len);\r
+    if ( new_node->data == NULL ) {\r
+        free(new_node);\r
+        return ccErrNoMem;\r
+    }\r
+    \r
+    memcpy(new_node->data,data,len);\r
+    new_node->len = len;\r
+       \r
+    if (head->head == NULL) { /*empty list*/\r
+        head->head = new_node;\r
+        head->tail = new_node;\r
+        new_node->prev = new_node->next = NULL;\r
+    } else {\r
+        new_node->next = head->head;\r
+        head->head->prev = new_node;\r
+        new_node->prev = NULL;\r
+        head->head = new_node;\r
+    }\r
+\r
+       if (nodepp != NULL)\r
+               *nodepp = new_node;\r
+\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_list_remove_element()\r
+ *\r
+ * Purpose: Remove a node from the list\r
+ *\r
+ * Return:  0, success\r
+ *         -1, failure\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ *\r
+ */\r
+cc_int32 \r
+cci_generic_list_remove_element(cc_generic_list_head_t* head, cc_generic_list_node_t* rem) \r
+{\r
+    if (head->head == NULL || rem == NULL)\r
+        return ccErrBadParam;\r
+\r
+    if (head->head == rem && head->tail == rem) { /*removing only element of list*/\r
+        head->head = head->tail = NULL;\r
+    } else if (head->head == rem) { /*removing head*/\r
+        head->head = head->head->next;\r
+    } else if (head->tail == rem) { /*removing tail*/\r
+        head->tail = head->tail->prev;\r
+        head->tail->next = NULL;\r
+    } else {\r
+        rem->prev->next = rem->next;\r
+        rem->next->prev = rem->prev;\r
+    }\r
+    free(rem);\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_free_element()\r
+ *\r
+ * Purpose: Free the memory associated with a node\r
+ *\r
+ * Return:  0, success\r
+ *         -1, failure\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_free_element(cc_generic_list_node_t* node)\r
+{\r
+    if ( node == NULL )\r
+        return ccErrBadParam;\r
+\r
+    if ( node->data ) {\r
+        free(node->data);\r
+        node->data = NULL;\r
+    }\r
+    node->len = 0;\r
+    node->next = node->prev = NULL;\r
+    free(node);\r
+    return ccNoError;\r
+}\r
+\r
+\r
+/**\r
+ * cci_generic_list_destroy()\r
+ *\r
+ * Purpose: Deallocate a list and all of its contents\r
+ *\r
+ * Return:  0, success\r
+ *         -1, failure\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ */\r
+cc_int32\r
+cci_generic_list_destroy(cc_generic_list_head_t* head) \r
+{\r
+    cc_generic_list_node_t *cur, *next;\r
+    cc_int32 ret = ccNoError;\r
+\r
+    if ( head == NULL )\r
+        return ccErrBadParam;\r
+       \r
+    for (cur = head->head; ret == ccNoError && cur != NULL; cur = next) {\r
+        next = cur->next;\r
+        ret = cci_generic_free_element(cur);\r
+    }       \r
+    free(head);\r
+    return(ret);\r
+}\r
+\r
+/**\r
+ * cci_generic_list_copy()\r
+ *\r
+ * Purpose: Copy a list\r
+ *\r
+ * Return:  non-NULL, a new list\r
+ *          NULL, failure\r
+ *\r
+ * Errors:  ccErrBadParam, ccErrNoMem\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_list_copy(cc_generic_list_head_t* head, cc_generic_list_head_t** headpp) \r
+{\r
+    cc_generic_list_head_t* copy;\r
+    cc_generic_list_node_t *src_node, *dst_node;\r
+    cc_int32 code;\r
+\r
+    if (head == NULL || headpp == NULL)\r
+        return ccErrBadParam;\r
+\r
+    code = cci_generic_list_new(&copy);\r
+    if (code != ccNoError)\r
+        return code;\r
+\r
+    for (src_node = head->head; src_node != NULL; src_node = src_node->next) {\r
+        code = cci_generic_list_append(copy, src_node->data, src_node->len, &dst_node);\r
+        if (code != ccNoError) {\r
+            cci_generic_list_destroy(copy);\r
+            return code;\r
+        }\r
+    }\r
+    *headpp = copy;\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_list_iterator()\r
+ *\r
+ * Purpose: Allocate an iterator for the specified list\r
+ *\r
+ * Return:  non-NULL, an iterator\r
+ *          NULL, failure\r
+ *\r
+ * Errors:  ccErrNoMem\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_list_iterator(cc_generic_list_head_t *head, cc_generic_iterate_t** headpp) \r
+{\r
+    cc_generic_iterate_t* iterator;\r
+\r
+    if ( head == NULL || headpp == NULL )\r
+        return ccErrBadParam;\r
+\r
+    iterator = (cc_generic_iterate_t*)malloc(sizeof(cc_generic_iterate_t));\r
+    if (iterator == NULL)\r
+        return ccErrNoMem;\r
+    \r
+    iterator->next = head->head;\r
+    *headpp = iterator;\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_generic_free_iterator()\r
+ *\r
+ * Purpose: Deallocate memory associated with an iterator\r
+ *\r
+ * Return:  0, success\r
+ *         -1, failure\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ *\r
+ */\r
+cc_int32\r
+cci_generic_free_iterator(cc_generic_iterate_t* iterator)\r
+{\r
+    if ( iterator == NULL )\r
+        return ccErrBadParam;\r
+\r
+    iterator->next = NULL;\r
+    free(iterator);\r
+    return ccNoError;\r
+}\r
+\r
+\r
+\r
diff --git a/src/lib/ccapi/common/marshall.c b/src/lib/ccapi/common/marshall.c
new file mode 100644 (file)
index 0000000..960019c
--- /dev/null
@@ -0,0 +1,440 @@
+/* $Copyright:\r
+ *\r
+ * Copyright 2004-2006 by the Massachusetts Institute of Technology.\r
+ * \r
+ * All rights reserved.\r
+ * \r
+ * Export of this software from the United States of America may require a\r
+ * specific license from the United States Government.  It is the\r
+ * responsibility of any person or organization contemplating export to\r
+ * obtain such a license before exporting.\r
+ * \r
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute\r
+ * this software and its documentation for any purpose and without fee is\r
+ * hereby granted, provided that the above copyright notice appear in all\r
+ * copies and that both that copyright notice and this permission notice\r
+ * appear in supporting documentation, and that the name of M.I.T. not be\r
+ * used in advertising or publicity pertaining to distribution of the\r
+ * software without specific, written prior permission.  Furthermore if you\r
+ * modify this software you must label your software as modified software\r
+ * and not distribute it in such a fashion that it might be confused with\r
+ * the original MIT software. M.I.T. makes no representations about the\r
+ * suitability of this software for any purpose.  It is provided "as is"\r
+ * without express or implied warranty.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ * \r
+ * Individual source code files are copyright MIT, Cygnus Support,\r
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.\r
+ * \r
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,\r
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology\r
+ * (MIT).  No commercial use of these trademarks may be made without prior\r
+ * written permission of MIT.\r
+ * \r
+ * "Commercial use" means use of a name in a product or other for-profit\r
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT\r
+ * trademarks in order to convey information (although in doing so,\r
+ * recognition of their trademark status should be given).\r
+ * $\r
+ */\r
+\r
+/* marshall.c */\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <CredentialsCache.h>\r
+#include "msg.h"\r
+#include "msg_headers.h"\r
+#include "marshall.h"\r
+\r
+cc_int32\r
+cci_creds_v4_marshall( cc_credentials_v4_t * creds, \r
+                       char ** pflat, \r
+                       cc_uint32 * plen)\r
+{\r
+    cc_uint32 len;\r
+    char * flat;\r
+    cci_flat_creds_v4_t * header;\r
+    cc_time64 t64;\r
+\r
+    if ( creds == NULL || pflat == NULL || plen == NULL )\r
+        return ccErrBadParam;\r
+\r
+    len = sizeof(cci_flat_creds_v4_t);\r
+    flat = (char *)malloc(len);\r
+    if ( flat == NULL )\r
+        return ccErrNoMem;\r
+    memset(flat, 0, len);\r
+\r
+    header = (cci_flat_creds_v4_t *)flat;\r
+    header->version = htonl(creds->version);\r
+    memcpy(header->principal, creds->principal, cc_v4_name_size);\r
+    memcpy(header->principal_instance, creds->principal_instance, cc_v4_instance_size);\r
+    memcpy(header->service, creds->service, cc_v4_name_size);\r
+    memcpy(header->service_instance, creds->service_instance, cc_v4_instance_size);\r
+    memcpy(header->realm, creds->realm, cc_v4_realm_size);\r
+    memcpy(header->session_key, creds->session_key, cc_v4_key_size);\r
+    header->kvno = htonl(creds->kvno);\r
+    header->string_to_key_type = htonl(creds->string_to_key_type);\r
+    t64 = creds->issue_date;\r
+    header->issue_date = htonll(t64);\r
+    header->lifetime = htonl(creds->lifetime);\r
+    /* TODO: verify that address is stored in host order */\r
+    header->address = htonl(creds->address);\r
+    header->ticket_size = htonl(creds->ticket_size);\r
+    memcpy(header->ticket, creds->ticket, cc_v4_ticket_size);\r
+\r
+    *pflat = flat;\r
+    *plen = len;\r
+\r
+    return ccNoError;  \r
+}\r
+\r
+cc_int32\r
+cci_creds_v4_unmarshall( char * flat, \r
+                         cc_uint32 len,\r
+                         cc_credentials_union * creds_union)\r
+{\r
+    struct cci_flat_creds_v4 * header;\r
+    cc_credentials_v4_t * creds;\r
+    cc_time64 t64;\r
+\r
+    if ( flat == NULL || len == 0 || creds_union == NULL )\r
+        return ccErrBadParam;\r
+\r
+    creds_union->version = cc_credentials_v4;\r
+\r
+    header = (cci_flat_creds_v4_t *)flat;\r
+\r
+    creds = (cc_credentials_v4_t *)malloc(sizeof(cc_credentials_v4_t));\r
+    if ( creds == NULL )\r
+       return ccErrNoMem;\r
+\r
+    creds->version = ntohl(header->version);\r
+    memcpy(creds->principal, header->principal, cc_v4_name_size);\r
+    memcpy(creds->principal_instance, header->principal_instance, cc_v4_instance_size);\r
+    memcpy(creds->service, header->service, cc_v4_name_size);\r
+    memcpy(creds->service_instance, header->service_instance, cc_v4_instance_size);\r
+    memcpy(creds->realm, header->realm, cc_v4_realm_size);\r
+    memcpy(creds->session_key, header->session_key, cc_v4_key_size);\r
+    creds->kvno = htonl(header->kvno);\r
+    creds->string_to_key_type = htonl(header->string_to_key_type);\r
+    t64 = header->issue_date;\r
+    creds->issue_date = (cc_time64)ntohll(t64);\r
+    creds->lifetime = (cc_int32)ntohl(header->lifetime);\r
+    /* TODO: verify that address is stored in host order */\r
+    creds->address = ntohl(header->address);\r
+    creds->ticket_size = ntohl(header->ticket_size);\r
+    memcpy(creds->ticket, header->ticket, cc_v4_ticket_size);\r
+\r
+    creds_union->credentials.credentials_v4 = creds;\r
+\r
+    return ccNoError;\r
+}\r
+\r
+\r
+cc_int32\r
+cci_creds_cc_data_array_count_entries( cc_data ** array, cc_uint32 * pcount)\r
+{\r
+    cc_uint32 count;\r
+\r
+    if (array == NULL) {\r
+        *pcount = 0;\r
+        return ccNoError;\r
+    }\r
+\r
+    for ( count=0; array[count] != NULL ; count++) ;\r
+\r
+    *pcount = count;\r
+    return ccNoError;\r
+}\r
+\r
+cc_int32\r
+cci_creds_v5_compute_flat_size( cc_credentials_v5_t * creds, cc_uint32 * plen)\r
+{\r
+    cc_uint32 len;\r
+    cc_uint32 i, count;\r
+\r
+    len = sizeof(struct cci_flat_creds_v5);\r
+\r
+    if (creds->client)\r
+        len += strlen(creds->client) + 1;\r
+\r
+    if (creds->server)\r
+        len += strlen(creds->server) + 1;\r
+\r
+    len += creds->keyblock.length;\r
+\r
+    cci_creds_cc_data_array_count_entries( creds->addresses, &count );\r
+    len += count * sizeof(cc_flat_data);\r
+    for ( i=0; i<count; i++ ) {\r
+        len += creds->addresses[i]->length;\r
+    }\r
+\r
+    len += creds->ticket.length;\r
+    len += creds->second_ticket.length;\r
+\r
+    cci_creds_cc_data_array_count_entries( creds->authdata, &count );\r
+    len += count * sizeof(cc_flat_data);\r
+    for ( i=0; i<count; i++ ) {\r
+        len += creds->authdata[i]->length;\r
+    }\r
+\r
+    *plen = len;\r
+    return ccNoError;\r
+}\r
+\r
+cc_int32\r
+cci_creds_v5_marshall( cc_credentials_v5_t * creds, \r
+                       char ** pflat, \r
+                       cc_uint32 * plen)\r
+{\r
+    cc_uint32 len;\r
+    char * flat;\r
+    struct cci_flat_creds_v5 * header;\r
+    cc_uint32 length;\r
+    cc_uint32 offset;\r
+    cc_time64 t64;\r
+    cc_uint32 count;\r
+    cc_uint32 i;\r
+\r
+    if ( creds == NULL || pflat == NULL || plen == NULL )\r
+        return ccErrBadParam;\r
+\r
+    cci_creds_v5_compute_flat_size(creds, &len);\r
+\r
+    flat = (char *)malloc(len);\r
+    if ( flat == NULL )\r
+        return ccErrNoMem;\r
+    memset(flat, 0, len);\r
+\r
+    offset = sizeof(struct cci_flat_creds_v5);\r
+    header = (struct cci_flat_creds_v5 *)flat;\r
+    header->version = htonl(FLAT_CREDS_V5_VERSION);\r
+    if (creds->client) {\r
+       length = strlen(creds->client) + 1;\r
+        header->client.length = htonl(length);\r
+        header->client.data = htonl(offset);\r
+        memcpy(flat + offset, creds->client, length);\r
+        offset += length;\r
+    }\r
+\r
+    if (creds->server) {\r
+       length = strlen(creds->server) + 1;\r
+        header->server.length = htonl(length);\r
+        header->server.data = htonl(offset);\r
+        memcpy(flat + offset, creds->server, length);\r
+        offset += length;\r
+    }\r
+\r
+    header->keyblock.type = htonl(creds->keyblock.type);\r
+    if (creds->keyblock.length) {\r
+       length = creds->keyblock.length;\r
+        header->keyblock.length = htonl(length);\r
+        header->keyblock.data = htonl(offset);\r
+        memcpy(flat + offset, creds->keyblock.data, length);\r
+        offset += length;\r
+    }           \r
+\r
+    t64 = creds->authtime;\r
+    header->authtime = htonll(t64);\r
+    t64 = creds->starttime;\r
+    header->starttime = htonll(t64);\r
+    t64 = creds->endtime;\r
+    header->endtime = htonll(t64);\r
+    t64 = creds->renew_till;\r
+    header->renew_till = htonll(t64);\r
+\r
+    header->is_skey = htonl(creds->is_skey);\r
+    header->ticket_flags = htonl(creds->ticket_flags);\r
+\r
+    cci_creds_cc_data_array_count_entries( creds->addresses, &count );\r
+    if ( count ) {\r
+        cc_flat_data * addresses = (cc_flat_data *)flat + offset;\r
+       header->address_count = htonl(count);\r
+        header->addresses = htonl(offset);\r
+        offset += count * sizeof(cc_flat_data);\r
+\r
+        for ( i=0; i < count; i++ ) {\r
+            addresses[i].type = htonl(creds->addresses[i]->type);\r
+            if (creds->addresses[i]->length) {\r
+               length = creds->addresses[i]->length;\r
+                addresses[i].length = htonl(length);\r
+                addresses[i].data = htonl(offset);\r
+               /* TODO: verify that addresses are stored in network order */\r
+                memcpy(flat + offset, creds->addresses[i]->data, length);\r
+                offset += length;\r
+            }\r
+        }\r
+    }\r
+\r
+    header->ticket.type = htonl(creds->ticket.type);\r
+    if (creds->ticket.length) {\r
+       length = creds->ticket.length;\r
+        header->ticket.length = htonl(length);\r
+        header->ticket.data = htonl(offset);\r
+        memcpy(flat + offset, creds->ticket.data, length);\r
+        offset += length;\r
+    }           \r
+\r
+    header->second_ticket.type = htonl(creds->second_ticket.type);\r
+    if (creds->second_ticket.length) {\r
+       length = creds->second_ticket.length;\r
+        header->second_ticket.length = htonl(length);\r
+        header->second_ticket.data = htonl(offset);\r
+        memcpy(flat + offset, creds->second_ticket.data, length);\r
+        offset += length;\r
+    }           \r
+\r
+    cci_creds_cc_data_array_count_entries( creds->authdata, &count );\r
+    if ( count ) {\r
+        cc_flat_data * authdata = (cc_flat_data *)flat + offset;\r
+\r
+       header->authdata_count = htonl(count);\r
+        header->authdata = (offset);\r
+        offset += count * sizeof(cc_flat_data);\r
+\r
+        for ( i=0; i < count; i++ ) {\r
+            authdata[i].type = htonl(creds->authdata[i]->type);\r
+            if (creds->authdata[i]->length) {\r
+               length = creds->authdata[i]->length;\r
+                authdata[i].length = htonl(length);\r
+                authdata[i].data = htonl(offset);\r
+                memcpy(flat + offset, creds->authdata[i]->data, length);\r
+                offset += length;\r
+            }\r
+        }\r
+    }\r
+\r
+    *pflat = flat;\r
+    *plen = len;\r
+    return ccNoError;\r
+}\r
+\r
+\r
+// TODO: a much better job of checking for out of memory errors\r
+//       and validating that we do not read beyond the flat input\r
+//       data buffer\r
+\r
+cc_int32\r
+cci_creds_v5_unmarshall( char * flat, \r
+                         cc_uint32 len,\r
+                         cc_credentials_union * creds_union)\r
+{\r
+    struct cci_flat_creds_v5 * header;\r
+    cc_credentials_v5_t * creds;\r
+    cc_flat_data * flat_data;\r
+    cc_time64 t64;\r
+    cc_uint32  length;\r
+    cc_uint32  count;\r
+    cc_uint32  i;\r
+\r
+    if ( flat == NULL || len == 0 || creds_union == NULL )\r
+        return ccErrBadParam;\r
+\r
+    creds_union->version = cc_credentials_v5;\r
+\r
+    header = (struct cci_flat_creds_v5 *)flat;\r
+\r
+    if ( ntohl(header->version) != FLAT_CREDS_V5_VERSION )\r
+        return ccErrBadParam;\r
+\r
+    creds = (cc_credentials_v5_t *)malloc(sizeof(cc_credentials_v5_t));\r
+    if ( creds == NULL )\r
+        return ccErrNoMem;\r
+    memset(creds, 0, sizeof(cc_credentials_v5_t));\r
+\r
+    if ( header->client.length ) {\r
+       length = ntohl(header->client.length);\r
+        creds->client = (char *)malloc(length);\r
+        memcpy(creds->client, flat + header->client.data, length);\r
+    }\r
+\r
+    if ( header->server.length ) {\r
+       length = ntohl(header->server.length);\r
+        creds->server = (char *)malloc(length);\r
+        memcpy(creds->server, flat + header->server.data, length);\r
+    }\r
+\r
+    creds->keyblock.type = ntohl(header->keyblock.type);\r
+    if ( header->keyblock.length ) {\r
+       length = ntohl(header->keyblock.length);\r
+        creds->keyblock.length = length;\r
+        creds->keyblock.data = malloc(length);\r
+        memcpy(creds->keyblock.data, flat + header->keyblock.data, length);\r
+    }\r
+\r
+    /* TODO: need to perform overflow validation checks to ensure\r
+     * that we do not attempt to store too large a value into cc_time_t\r
+     * when it is a 32-bit field.\r
+     */\r
+    t64 = ntohll(header->authtime);\r
+    creds->authtime = (cc_time)t64;\r
+    t64 = ntohll(header->starttime);\r
+    creds->starttime = (cc_time)t64;\r
+    t64 = ntohll(header->endtime);\r
+    creds->endtime = (cc_time)t64;\r
+    t64 = ntohll(header->renew_till);\r
+    creds->renew_till = (cc_time)t64;\r
+\r
+    creds->is_skey = ntohl(header->is_skey);\r
+    creds->ticket_flags = ntohl(header->ticket_flags);\r
+\r
+    count = ntohl(header->address_count);\r
+    creds->addresses = (cc_data **) malloc((count + 1) * sizeof(cc_data *));\r
+    flat_data = (cc_flat_data *)flat + header->addresses;\r
+    for ( i=0 ; i < count ; i++ ) {\r
+        creds->addresses[i] = (cc_data *)malloc(sizeof(cc_data));\r
+        creds->addresses[i]->type = ntohl(flat_data[i].type);\r
+       length = ntohl(flat_data[i].length);\r
+        creds->addresses[i]->length = length;\r
+        if ( length ) {\r
+            creds->addresses[i]->data = malloc(length);\r
+           /* TODO: verify that addresses are stored in network order */\r
+            memcpy(creds->addresses[i]->data, flat + flat_data[i].data, length);\r
+        } else {\r
+            creds->addresses[i]->data = NULL;\r
+        }\r
+    }\r
+    creds->addresses[i] = NULL;\r
+\r
+    creds->ticket.type = ntohl(header->ticket.type);\r
+    length = ntohl(header->ticket.length);\r
+    if ( length ) {\r
+        creds->ticket.length = length;\r
+        creds->ticket.data = malloc(length);\r
+        memcpy(creds->ticket.data, flat + header->ticket.data, length);\r
+    }\r
+\r
+    creds->second_ticket.type = header->second_ticket.type;\r
+    if ( header->second_ticket.length ) {\r
+        creds->second_ticket.length = header->second_ticket.length;\r
+        creds->second_ticket.data = malloc(creds->second_ticket.length);\r
+        memcpy(creds->second_ticket.data, flat + header->second_ticket.data, creds->second_ticket.length);\r
+    }\r
+\r
+    count = ntohl(header->authdata_count);\r
+    creds->authdata = (cc_data **) malloc((count + 1) * sizeof(cc_data *));\r
+    flat_data = (cc_flat_data *)flat + header->authdata;\r
+    for ( i=0 ; i < count ; i++ ) {\r
+        creds->authdata[i] = (cc_data *)malloc(sizeof(cc_data));\r
+        creds->authdata[i]->type = ntohl(flat_data[i].type);\r
+       length = ntohl(flat_data[i].length);\r
+        creds->authdata[i]->length = length;\r
+        if ( length ) {\r
+            creds->authdata[i]->data = malloc(length);\r
+            memcpy(creds->authdata[i]->data, flat + flat_data[i].data, length);\r
+        } else {\r
+            creds->authdata[i]->data = NULL;\r
+        }\r
+    }\r
+    creds->authdata[i] = NULL;\r
+\r
+    creds_union->credentials.credentials_v5 = creds;\r
+\r
+    return ccNoError;\r
+}\r
+\r
diff --git a/src/lib/ccapi/common/msg.c b/src/lib/ccapi/common/msg.c
new file mode 100644 (file)
index 0000000..b7f60dd
--- /dev/null
@@ -0,0 +1,628 @@
+/* $Copyright:\r
+ *\r
+ * Copyright 2004-2006 by the Massachusetts Institute of Technology.\r
+ * \r
+ * All rights reserved.\r
+ * \r
+ * Export of this software from the United States of America may require a\r
+ * specific license from the United States Government.  It is the\r
+ * responsibility of any person or organization contemplating export to\r
+ * obtain such a license before exporting.\r
+ * \r
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute\r
+ * this software and its documentation for any purpose and without fee is\r
+ * hereby granted, provided that the above copyright notice appear in all\r
+ * copies and that both that copyright notice and this permission notice\r
+ * appear in supporting documentation, and that the name of M.I.T. not be\r
+ * used in advertising or publicity pertaining to distribution of the\r
+ * software without specific, written prior permission.  Furthermore if you\r
+ * modify this software you must label your software as modified software\r
+ * and not distribute it in such a fashion that it might be confused with\r
+ * the original MIT software. M.I.T. makes no representations about the\r
+ * suitability of this software for any purpose.  It is provided "as is"\r
+ * without express or implied warranty.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ * \r
+ * Individual source code files are copyright MIT, Cygnus Support,\r
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.\r
+ * \r
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,\r
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology\r
+ * (MIT).  No commercial use of these trademarks may be made without prior\r
+ * written permission of MIT.\r
+ * \r
+ * "Commercial use" means use of a name in a product or other for-profit\r
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT\r
+ * trademarks in order to convey information (although in doing so,\r
+ * recognition of their trademark status should be given).\r
+ * $\r
+ */\r
+\r
+/*\r
+ * Verifiable, extensible message format.\r
+ *\r
+ * Format:\r
+ * <size of header block (header_len)>\r
+ * <size of *entire* message, including previous field (flat_len)>\r
+ * <message type (type)>\r
+ * <type specific header (header)>\r
+ * <magic number (magic)>\r
+ * <data blob 1 length>\r
+ * <data blob 1>\r
+ * <data blob 2 length>\r
+ * <data blob 2>\r
+ * ...\r
+ * <magic number (magic)>\r
+ *\r
+ * If the header has variable length data it is included in the data blobs. \r
+ * The header field has the offset from the beginning of the message of the 1st \r
+ * byte of the data and the length of the data.\r
+ */\r
+\r
+#include "CredentialsCache.h"\r
+#include "msg.h"\r
+#include "generic_lists.h"\r
+\r
+#include <stdlib.h>\r
+#include <memory.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+/**\r
+ * cci_msg_new()\r
+ *\r
+ * Purpose: Allocate and initialize a new cc_msg_t structure\r
+ *\r
+ * Input parameter (type) in host order\r
+ *\r
+ * Return:  non-NULL, the msg\r
+ *          NULL, failure\r
+ *\r
+ * Errors:  ccErrNoMem\r
+ *\r
+ */\r
+cc_int32\r
+cci_msg_new(cc_uint32 type, cc_msg_t** msgpp) \r
+{\r
+    // type should be validated.  If invalid set error to ccErrBadParam\r
+    cc_msg_t* msg;\r
+    \r
+    if ( type > CC_MSG_MAX_TYPE || msgpp == NULL )\r
+        return ccErrBadParam;\r
+\r
+    msg = (cc_msg_t*)malloc(sizeof(cc_msg_t));\r
+    if (msg == NULL)\r
+        return ccErrNoMem;\r
+\r
+    msg->type = htonl(type);\r
+    msg->flat = NULL;\r
+    msg->header = NULL;\r
+    msg->flat_len = 0;\r
+    msg->header_len = 0;\r
+    msg->magic = 0;\r
+    cci_generic_list_new(&msg->data_blobs);\r
+    if (msg->data_blobs == NULL) {\r
+        // pass on error from previous call\r
+        free(msg);\r
+        return ccErrNoMem;\r
+    }\r
+\r
+    *msgpp = msg;     \r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_msg_calc_header_size()\r
+ *\r
+ * Purpose: Calculates the size of the header\r
+ *\r
+ * Return:  the size in bytes\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ *\r
+ */\r
+cc_int32\r
+cci_msg_calc_header_size(cc_msg_t* msg, cc_uint32 * lenp) \r
+{\r
+    int header_len = 12; /* header size, entire size, type */\r
+\r
+    if ( msg == NULL || lenp == NULL )\r
+        return ccErrBadParam;\r
+\r
+    header_len += msg->header_len;\r
+    *lenp = header_len;\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cci_msg_calc_size()\r
+ *\r
+ * Purpose: Calculates the size of the message\r
+ *          (does not include the magic bytes)\r
+ *\r
+ * Return:  the size in bytes\r
+ *\r
+ * Errors:  ccErrBadParam\r
+ *\r
+ */\r
+cc_int32 \r
+cci_msg_calc_size(cc_msg_t* msg, cc_uint32 * lenp) \r
+{\r
+    cc_uint32 flat_len;\r
+    cc_generic_list_node_t* gen_node;\r
+    cc_generic_iterate_t* gen_iterator;\r
+       cc_int32 code;\r
+\r
+    if ( msg == NULL || lenp == NULL ) \r
+        return ccErrBadParam;\r
+\r
+    code = cci_msg_calc_header_size(msg, &flat_len);\r
+    if (code != ccNoError)\r
+        goto bad;\r
+\r
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);\r
+    if ( code != ccNoError )\r
+        goto bad;\r
+\r
+    while (cci_generic_iterate_has_next(gen_iterator)) {\r
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);\r
+        if (code != ccNoError)\r
+            break;\r
+        flat_len += gen_node->len + BLOB_LEN;\r
+    }\r
+    cci_generic_free_iterator(gen_iterator);\r
+    if (code != ccNoError)\r
+        goto bad;\r
+\r
+    flat_len += MAGIC_HEAD_LEN + MAGIC_DATA_LEN;\r
+    *lenp = flat_len;\r
+\r
+  bad:\r
+    return code;\r
+}\r
+\r
+/**\r
+ * cci_msg_add_data_blob()\r
+ *\r
+ * Purpose: Adds 'len' bytes of data to the msg\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32 \r
+cci_msg_add_data_blob(cc_msg_t* msg, void *data, cc_uint32 len, cc_uint32 *lenp) \r
+{\r
+    cc_int32 code;\r
+\r
+    if (msg == NULL || data == NULL || len <= 0 || lenp == NULL)\r
+        return ccErrBadParam;\r
+\r
+    code = cci_generic_list_append(msg->data_blobs, data, len, NULL);\r
+    if ( code != ccNoError )\r
+        return code;\r
+    return cci_msg_calc_blob_pos(msg, data, len, lenp);\r
+}\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32 \r
+cci_msg_calc_blob_pos(cc_msg_t* msg, void *data, cc_uint32 len, cc_uint32 * posp) \r
+{\r
+    cc_uint32 pos;\r
+    cc_generic_list_node_t* gen_node;\r
+    cc_generic_iterate_t* gen_iterator;\r
+    cc_int32 code;\r
+\r
+    code = cci_msg_calc_header_size(msg, &pos);\r
+    pos += sizeof(cc_uint32); /*+ sizeof(cc_uint32) for magic*/\r
+\r
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);\r
+    while (cci_generic_iterate_has_next(gen_iterator)) {\r
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);\r
+        if (gen_node->len != len && gen_node->data != data) {\r
+            pos += gen_node->len + sizeof(cc_uint32);\r
+        } else {\r
+            cci_generic_free_iterator(gen_iterator);\r
+            *posp = pos + sizeof(cc_uint32);\r
+            return ccNoError;\r
+        }\r
+    }\r
+    \r
+    cci_generic_free_iterator(gen_iterator);\r
+    return ccIteratorEnd;\r
+}\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32 \r
+cci_msg_add_header(cc_msg_t* msg, void *header, cc_uint32 header_len) \r
+{\r
+    if ( msg == NULL || header == NULL )\r
+        return ccErrBadParam;\r
+\r
+    msg->header = header;\r
+    msg->header_len = header_len;\r
+    return ccNoError;\r
+}\r
+\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32\r
+cci_msg_flatten(cc_msg_t* msg, void **flatpp) \r
+{\r
+    cc_generic_list_node_t* gen_node;\r
+    cc_generic_iterate_t* gen_iterator;\r
+    char *cur_pos;\r
+    cc_uint32 zero = 0;\r
+    cc_uint32 magic = 0;\r
+    cc_uint32 msg_len;\r
+    cc_uint32 u32;\r
+    cc_int32 code;\r
+\r
+    if (msg == NULL || flatpp == NULL)\r
+        return ccErrBadParam;\r
+\r
+    code = cci_msg_calc_size(msg,&msg->flat_len);\r
+    if ( code != ccNoError )\r
+        return code;\r
+\r
+    if (msg->flat_len > CC_MSG_MAX_SIZE)\r
+        return ccErrBadParam;\r
+\r
+    msg->flat = (void *)malloc(msg->flat_len);\r
+    if (msg->flat == NULL)\r
+        return ccErrNoMem;\r
+    \r
+    cur_pos = msg->flat;\r
+\r
+    u32 = msg->header_len;\r
+    htonl(u32);\r
+    memcpy(cur_pos,&u32,sizeof(cc_uint32));\r
+    cur_pos+=sizeof(cc_uint32);\r
+\r
+    u32 = msg->flat_len;\r
+    htonl(u32);\r
+    memcpy(cur_pos,&u32,sizeof(cc_uint32));\r
+    cur_pos+=sizeof(cc_uint32);\r
+\r
+    u32 = msg->type;\r
+    htonl(u32);\r
+    memcpy(cur_pos,&u32,sizeof(cc_uint32));\r
+    cur_pos+=sizeof(cc_uint32);\r
+\r
+    /* header data is already in network order */\r
+    memcpy(cur_pos, msg->header, msg->header_len);\r
+    cur_pos += msg->header_len;\r
+\r
+    u32 = zero;\r
+    htonl(zero);\r
+    memcpy(cur_pos, &u32, sizeof(cc_uint32)); /*will be magic number later*/\r
+    cur_pos += sizeof(cc_uint32);\r
+\r
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);\r
+    if ( code != ccNoError ) {\r
+        free(msg->flat);\r
+        return code;\r
+    }\r
+\r
+    while (cci_generic_iterate_has_next(gen_iterator)) {\r
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);\r
+        if (code != ccNoError) {\r
+            free(gen_iterator);\r
+            free(msg->flat);\r
+            return code;\r
+        }\r
+       u32 = gen_node->len;\r
+       htonl(u32);\r
+        memcpy(cur_pos, &u32, sizeof(cc_uint32));\r
+        cur_pos+=sizeof(cc_uint32);\r
+               \r
+       /* data already in network order */\r
+        memcpy(cur_pos, gen_node->data, gen_node->len);\r
+        cur_pos += gen_node->len;\r
+    }\r
+    free(gen_iterator);\r
+\r
+    u32 = zero;\r
+    htonl(zero);\r
+    memcpy(cur_pos, &u32, sizeof(cc_uint32)); /*magic number will go here later*/\r
+    cur_pos += sizeof(cc_uint32);\r
+\r
+    if (cur_pos - (char *)msg->flat != msg->flat_len) {\r
+        fprintf(stderr, "ERROR cur_pos - msg->flat = %d\n",msg->flat_len);\r
+    }\r
+\r
+    cci_msg_calc_magic(msg->flat, msg->flat_len, &magic);\r
+    printf("magic = %d\n",magic);\r
+       \r
+    cci_msg_calc_header_size(msg, &msg_len);\r
+    memcpy((char *)msg->flat + msg_len, &magic, sizeof(cc_uint32));\r
+    memcpy((char *)msg->flat + msg->flat_len - sizeof(cc_uint32), &magic, sizeof(cc_uint32));\r
+\r
+    if ( flatpp != NULL )\r
+        *flatpp = msg->flat;\r
+\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32\r
+cci_msg_calc_magic(void *flat, int flat_len, cc_uint32 * magicp)\r
+{\r
+    cc_uint32 magic = 0;\r
+    int i;\r
+       \r
+    for (i = 0; i < flat_len; i += sizeof(cc_uint32)) {\r
+        magic = magic ^ *(int *)((char *)flat + i);\r
+    }\r
+    *magicp = htonl(magic);\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32 \r
+cci_msg_verify(void *flat, int flat_len, cc_uint32 * validp)  \r
+{\r
+    cc_uint32 *magic1, *magic2;\r
+    cc_uint32 *pheader_len;\r
+    cc_uint32 header_len;\r
+    cc_uint32 *ptotal_len;\r
+    cc_uint32 total_len;\r
+    cc_uint32 *pblob_len;\r
+    cc_uint32 blob_len;\r
+    cc_uint32 *ptype;\r
+    cc_uint32 type;\r
+    cc_uint32 num_blobs = 0;\r
+    cc_uint32 zero = 0;\r
+    cc_uint32 msg_magic, msg_magic2;\r
+\r
+    if (flat == NULL || flat_len <= 0 || validp == NULL)\r
+        return ccErrBadParam;\r
+\r
+    pheader_len = flat;\r
+    ptotal_len = (cc_uint32 *)((char *)pheader_len + sizeof(cc_uint32));\r
+    ptype = (cc_uint32 *)((char *)ptotal_len + sizeof(cc_uint32));\r
+\r
+    header_len = ntohl(*pheader_len);\r
+    total_len = ntohl(*ptotal_len);\r
+    type = ntohl(*ptype);\r
+\r
+    if (total_len != flat_len) {\r
+        *validp = 0;\r
+        return ccNoError;\r
+    }\r
+    \r
+    if (header_len > flat_len) {\r
+        /*too weak. We could verify header_len against type spec header.*/\r
+        *validp = 0;\r
+        return ccNoError;\r
+    }\r
+    if (type > CC_MSG_MAX_TYPE) {\r
+        *validp = 0;\r
+        return ccNoError;\r
+    }\r
+\r
+    magic1 = (cc_uint32 *)((char *)ptype + sizeof(cc_uint32) + header_len); \r
+    if ((char *)magic1 - (char *)flat == (flat_len - 8)) {\r
+        /*There are no data blobs*/\r
+        magic2 = (cc_uint32 *)((char *)magic1 + sizeof(cc_uint32));\r
+        num_blobs = 0;\r
+    } else {\r
+        pblob_len = (cc_uint32 *)((char *)magic1 + sizeof(cc_uint32));\r
+        num_blobs = 1;\r
+       blob_len = ntohl(*pblob_len);\r
+\r
+        while (blob_len + sizeof(cc_uint32) + ((char *)pblob_len - (char *)flat) < (flat_len - sizeof(cc_uint32))) {\r
+            pblob_len = (cc_uint32 *)((char *)pblob_len + blob_len + sizeof(cc_uint32));\r
+            num_blobs++;\r
+           blob_len = ntohl(*pblob_len);\r
+        }\r
+\r
+        if (blob_len + sizeof(cc_uint32) + ((char *)pblob_len - (char *)flat) != (flat_len - sizeof(cc_uint32))) {\r
+            /*blobs didn't line up*/\r
+            *validp = 0;\r
+            return ccNoError;\r
+        }\r
+        magic2 = (cc_uint32 *)((char *)pblob_len + blob_len + sizeof(cc_uint32)); /*2nd magic should be directly after the last blob*/\r
+    }\r
+       \r
+    if (*magic1 != *magic2) {\r
+        *validp = 0;\r
+        return ccNoError;\r
+    }\r
+    msg_magic = *magic1;\r
+\r
+    printf("%d %d\n", (char *)magic1 - (char *)flat, (char *)magic2 - (char *)flat);\r
+\r
+    memcpy(magic1, &zero, sizeof(cc_uint32));\r
+    memcpy(magic2, &zero, sizeof(cc_uint32));\r
+    cci_msg_calc_magic(flat, flat_len, &msg_magic2);\r
+    /* both msg_magic and msg_magic2 are in network order */\r
+    if (msg_magic != msg_magic2) {\r
+        *validp = 0;\r
+        return ccNoError;\r
+    }\r
+    memcpy(magic1, &msg_magic, sizeof(cc_uint32));\r
+    memcpy(magic2, &msg_magic, sizeof(cc_uint32));\r
+\r
+    *validp = 1;\r
+    return ccNoError;\r
+}\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32\r
+cci_msg_unflatten(void *flat, int flat_len, cc_msg_t** msgpp) \r
+{\r
+    cc_msg_t* msg;\r
+    char *cur_pos;\r
+    cc_uint32 blob_len;\r
+    char *blob;\r
+    cc_uint32 valid;\r
+    cc_int32 code;\r
+\r
+    if ( flat == NULL || flat_len <= 0 || msgpp == NULL )\r
+        return ccErrBadParam;\r
+\r
+    code = cci_msg_new(0, &msg);\r
+    if (code)\r
+        return code;\r
+\r
+    cci_msg_verify(flat, flat_len, &valid);\r
+    if (valid != 1) {\r
+        cci_msg_destroy(msg);\r
+        return ccErrBadParam;\r
+    }\r
+\r
+    cur_pos = flat;\r
+    msg->flat = flat;\r
+\r
+    msg->header_len = ntohl(*(cc_uint32 *)cur_pos);\r
+    cur_pos += sizeof(cc_uint32);\r
+\r
+    msg->flat_len = ntohl(*(cc_uint32 *)cur_pos);\r
+    cur_pos += sizeof(cc_uint32);\r
+\r
+    msg->type = ntohl(*(cc_uint32 *)cur_pos);\r
+    cur_pos += sizeof(cc_uint32);\r
+\r
+    msg->header = (void *)malloc(msg->header_len);\r
+    if (msg->header == NULL) {\r
+        cci_msg_destroy(msg);\r
+        return ccErrNoMem;\r
+    }\r
+    memcpy(msg->header, cur_pos, msg->header_len);\r
+    cur_pos += msg->header_len;\r
+       \r
+    msg->magic = ntohl(*(cc_uint32 *)cur_pos);\r
+    cur_pos += sizeof(cc_uint32);\r
+\r
+    if (cur_pos - (char *)flat != flat_len - 8) { /*at least 1 blob*/\r
+        blob_len = ntohl(*(cc_uint32 *)cur_pos);\r
+        while (blob_len + (cur_pos - (char *)flat) + sizeof(cc_uint32) <= flat_len - sizeof(cc_uint32)) {\r
+            blob = (void *)malloc(blob_len);\r
+            if (blob == NULL) {\r
+                cci_msg_destroy(msg);\r
+                return ccErrNoMem;\r
+            }\r
+            memcpy(blob, cur_pos + sizeof(cc_uint32), blob_len);\r
+            cci_generic_list_append(msg->data_blobs, blob, blob_len, NULL);\r
+\r
+            cur_pos += sizeof(cc_uint32) + blob_len;\r
+            blob_len = ntohl(*(int *)cur_pos);\r
+        }\r
+    }\r
+    *msgpp = msg;\r
+    return ccNoError;\r
+}\r
+\r
+cc_int32\r
+cci_msg_retrieve_blob(cc_msg_t* msg, cc_uint32 blob_offset, cc_uint32 blob_len, void **blobp) \r
+{\r
+    cc_generic_iterate_t*      gen_iterator;\r
+    cc_generic_list_node_t*    gen_node;\r
+    void *ret;\r
+    cc_uint32                   blob_pos;\r
+    cc_int32                    code;\r
+\r
+    /*Ensure that the message has been unflattened*/\r
+    if ( msg == NULL || msg->flat == NULL || blob_offset > msg->flat_len || \r
+         blob_len > msg->flat_len - blob_offset || blobp == NULL)\r
+        return ccErrBadParam;\r
+\r
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);\r
+    while (cci_generic_iterate_has_next(gen_iterator)) {\r
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);\r
+        code = cci_msg_calc_blob_pos(msg, gen_node->data, gen_node->len, &blob_pos);\r
+        if (blob_pos == blob_offset && gen_node->len == blob_len)  {\r
+            free(gen_iterator);\r
+            ret = (void *)malloc(blob_len);\r
+            if (ret == NULL)\r
+                return ccErrNoMem;\r
+            memcpy(ret,(char *)msg->flat + blob_offset, blob_len);     \r
+            *blobp = ret;\r
+            return ccNoError;\r
+        }\r
+    }\r
+    free(gen_iterator);\r
+    return ccIteratorEnd;\r
+}\r
+\r
+/**\r
+ * cc_msg_\r
+ *\r
+ * Purpose:\r
+ *\r
+ * Return: \r
+ *\r
+ * Errors: \r
+ *\r
+ */\r
+cc_int32 \r
+cci_msg_destroy(cc_msg_t* msg) \r
+{\r
+    if (msg->flat != NULL) \r
+        free(msg->flat);\r
+    if (msg->header != NULL)\r
+        free(msg->flat);\r
+    cci_generic_list_destroy(msg->data_blobs);\r
+    free(msg);\r
+    return ccNoError;\r
+}\r
+\r