lasso/lasso/xml/xml.c

1489 lines
38 KiB
C

/* $Id$
*
* Lasso - A free implementation of the Liberty Alliance specifications.
*
* Copyright (C) 2004 Entr'ouvert
* http://lasso.entrouvert.org
*
* Authors: Nicolas Clapies <nclapies@entrouvert.com>
* Valery Febvre <vfebvre@easter-eggs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <lasso/xml/errors.h>
#include <lasso/xml/xml.h>
#include <lasso/xml/ds_signature.h>
#include <xmlsec/base64.h>
#include <xmlsec/xmltree.h>
struct _LassoNodePrivate
{
gboolean dispose_has_run;
gboolean node_is_weak_ref;
xmlNodePtr node;
};
static GObjectClass *parent_class = NULL;
/*****************************************************************************/
/* virtual public methods */
/*****************************************************************************/
static void lasso_node_impl_set_xmlNode(LassoNode *node, xmlNodePtr libxml_node);
/**
* lasso_node_copy:
* @node: a LassoNode
*
* Build a copy of the node.
*
* Return value: a copy of the node
**/
LassoNode *
lasso_node_copy(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->copy(node));
}
/**
* lasso_node_dump:
* @node: a LassoNode
* @encoding: the name of the encoding to use or NULL.
* @format: is formatting allowed
*
* Dumps @node. All datas in object are dumped in an XML format.
*
* Return value: a full XML dump of @node
**/
xmlChar *
lasso_node_dump(LassoNode *node,
const xmlChar *encoding,
int format)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->dump(node, encoding, format));
}
/**
* lasso_node_destroy:
* @node: a LassoNode
*
* Destroys the LassoNode.
**/
void
lasso_node_destroy(LassoNode *node)
{
if (node != NULL) {
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->destroy(node));
}
return;
}
/**
* lasso_node_export:
* @node: a LassoNode
*
* Exports the LassoNode.
*
* Return value: an XML dump of the LassoNode (UTF-8 encoding)
**/
xmlChar *
lasso_node_export(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->export(node));
}
/**
* lasso_node_export_to_base64:
* @node: a LassoNode
*
* Like lasso_node_export() method except that result is Base64 encoded.
*
* Return value: a Base64 encoded export of the LassoNode
**/
xmlChar *
lasso_node_export_to_base64(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->export_to_base64(node));
}
/**
* lasso_node_export_to_query:
* @node: a LassoNode
* @sign_method: the Signature transform method
* @private_key_file: a private key (may be NULL)
*
* URL-encodes and signes the LassoNode.
* If private_key_file is NULL, query won't be signed.
*
* Return value: URL-encoded and signed LassoNode
**/
gchar *
lasso_node_export_to_query(LassoNode *node,
lassoSignatureMethod sign_method,
const gchar *private_key_file)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->export_to_query(node, sign_method, private_key_file));
}
/**
* lasso_node_export_to_soap:
* @node: a LassoNode
*
* Like lasso_node_export() method except that result is SOAP enveloped.
*
* Return value: a SOAP enveloped export of the LassoNode
**/
xmlChar *
lasso_node_export_to_soap(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->export_to_soap(node));
}
/**
* lasso_node_get_attr:
* @node: a LassoNode
* @name: the attribute name
*
* Gets an attribute associated with the node.
*
* Return value: the attribute or NULL if not found.
**/
LassoAttr *
lasso_node_get_attr(LassoNode *node,
const xmlChar *name)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_attr(node, name));
}
/**
* lasso_node_get_attr_value:
* @node: a LassoNode
* @name: the attribute name
* @err: return location for an allocated GError, or NULL to ignore errors
*
* Gets the value of an attribute associated to a node.
*
* Return value: the attribute value or NULL if not found. It's up to the caller
* to free the memory with xmlFree().
**/
xmlChar *
lasso_node_get_attr_value(LassoNode *node,
const xmlChar *name,
GError **err)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_attr_value(node, name, err));
}
/**
* lasso_node_get_attrs:
* @node: a LassoNode
*
* Gets attributes associated with the node.
*
* Return value: an array of attributes or NULL if no attribute found.
**/
GPtrArray *
lasso_node_get_attrs(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_attrs(node));
}
/**
* lasso_node_get_child:
* @node: a LassoNode
* @name: the child name
* @href: the namespace (may be NULL)
*
* Gets child of node having given @name and namespace @href.
*
* Return value: a child node
**/
LassoNode *
lasso_node_get_child(LassoNode *node,
const xmlChar *name,
const xmlChar *href)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_child(node, name, href));
}
/**
* lasso_node_get_child_content:
* @node: a LassoNode
* @name: the child name
* @href: the namespace (may be NULL)
*
* Gets child content of node having given @name and namespace @href.
*
* Return value: a new xmlChar * or NULL if no child found or no content is
* available. It's up to the caller to free the memory with xmlFree().
**/
xmlChar *
lasso_node_get_child_content(LassoNode *node,
const xmlChar *name,
const xmlChar *href)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_child_content(node, name, href));
}
/**
* lasso_node_get_children:
* @node: a LassoNode
*
* Gets direct children of node.
*
* Return value: an array of node or NULL if no children found.
**/
GPtrArray *
lasso_node_get_children(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_children(node));
}
/**
* lasso_node_get_content:
* @node: a LassoNode
*
* Read the value of a node, this can be either the text carried directly by
* this node if it's a TEXT node or the aggregate string of the values carried
* by this node child's (TEXT and ENTITY_REF). Entity references are
* substituted.
*
* Return value: a new xmlChar * or NULL if no content is available.
* It's up to the caller to free the memory with xmlFree().
**/
xmlChar *
lasso_node_get_content(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_content(node));
}
/**
* lasso_node_get_name:
* @node: a LassoNode
*
* Gets the name of the node.
*
* Return value: the name of the node
**/
const xmlChar *
lasso_node_get_name(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_name(node));
}
/**
* lasso_node_import:
* @node: a LassoNode
* @buffer: an XML buffer
*
* Parses the XML buffer and loads it into the node.
**/
void
lasso_node_import(LassoNode *node,
const xmlChar *buffer)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->import(node, buffer);
}
/**
* lasso_node_import_from_node:
* @node: a LassoNode
* @imported_node: a LassoNode
*
* Put a copy of node->private->node into imported_node->private->node
**/
void
lasso_node_import_from_node(LassoNode *node,
LassoNode *imported_node)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->import_from_node(node, imported_node);
}
/**
* lasso_node_rename_prop:
* @node: a LassoNode
* @old_name: the attribute name
* @new_name: the new attribute name
*
* Renames an attribute of the node.
**/
void
lasso_node_rename_prop(LassoNode *node,
const xmlChar *old_name,
const xmlChar *new_name)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->rename_prop(node, old_name, new_name);
}
/**
* lasso_node_verify_signature:
* @node: a LassoNode
* @certificate_file: a certificate
*
* Verifys the node signature.
*
* Return value: 1 if signature is valid, 0 if invalid. -1 if an error occurs.
**/
gint
lasso_node_verify_signature(LassoNode *node,
const gchar *certificate_file)
{
g_return_val_if_fail (LASSO_IS_NODE(node), -1);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->verify_signature(node, certificate_file));
}
/*****************************************************************************/
/* virtual private methods */
/*****************************************************************************/
static void
lasso_node_add_child(LassoNode *node,
LassoNode *child,
gboolean unbounded)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->add_child(node, child, unbounded);
}
static gint
lasso_node_add_signature(LassoNode *node,
gint sign_method,
const xmlChar *private_key_file,
const xmlChar *certificate_file)
{
g_return_val_if_fail(LASSO_IS_NODE(node), -1);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->add_signature(node, sign_method, private_key_file, certificate_file));
}
static gchar *
lasso_node_build_query(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->build_query(node));
}
static xmlNodePtr
lasso_node_get_xmlNode(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->get_xmlNode(node));
}
/**
* lasso_node_new_child:
* @node: a LassoNode
* @name: the name of the child
* @content: the content of the child
* @unbounded: if TRUE, several children with the same name can be added else
* the child must be unique.
*
* Add a new child in node.
* This is an internal function and should not be called by application
* directly.
**/
static void
lasso_node_new_child(LassoNode *node,
const xmlChar *name,
const xmlChar *content,
gboolean unbounded)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->new_child(node, name, content, unbounded);
}
static GData *
lasso_node_serialize(LassoNode *node,
GData *gd)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
return (class->serialize(node, gd));
}
static void
lasso_node_set_name(LassoNode *node,
const xmlChar *name)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->set_name(node, name);
}
static void
lasso_node_set_ns(LassoNode *node,
const xmlChar *href,
const xmlChar *prefix)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->set_ns(node, href, prefix);
}
static void
lasso_node_set_prop(LassoNode *node,
const xmlChar *name,
const xmlChar *value)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->set_prop(node, name, value);
}
static void
lasso_node_set_xmlNode(LassoNode *node,
xmlNodePtr libxml_node)
{
g_return_if_fail(LASSO_IS_NODE(node));
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
class->set_xmlNode(node, libxml_node);
}
/*****************************************************************************/
/* implementation methods */
/*****************************************************************************/
static LassoNode *
lasso_node_impl_copy(LassoNode *node)
{
LassoNode *copy;
copy = LASSO_NODE(g_object_new(G_OBJECT_TYPE(node), NULL));
copy->private->node = xmlCopyNode(node->private->node, 1);
/* copy = lasso_node_new_from_xmlNode(xmlCopyNode(node->private->node, 1)); */
/* copy->private->node_is_weak_ref = FALSE; */
return (copy);
}
static void
lasso_node_impl_destroy(LassoNode *node)
{
g_object_unref(G_OBJECT(node));
}
static xmlChar *
lasso_node_impl_dump(LassoNode *node,
const xmlChar *encoding,
int format)
{
xmlChar *ret;
int len;
xmlOutputBufferPtr buf;
xmlCharEncodingHandlerPtr handler = NULL;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
/* encoding is optional */
g_return_val_if_fail (format == 0 || format == 1, NULL);
if (encoding != NULL) {
handler = xmlFindCharEncodingHandler(encoding);
if (handler == NULL) {
return (NULL);
}
}
buf = xmlAllocOutputBuffer(handler);
if (buf == NULL) {
return (NULL);
}
xmlNodeDumpOutput(buf, node->private->node->doc, node->private->node,
0, format, encoding);
xmlOutputBufferFlush(buf);
if (buf->conv != NULL) {
len = buf->conv->use;
ret = buf->conv->content;
buf->conv->content = NULL;
}
else {
len = buf->buffer->use;
ret = buf->buffer->content;
buf->buffer->content = NULL;
}
(void) xmlOutputBufferClose(buf);
return (ret);
}
static xmlChar *
lasso_node_impl_export(LassoNode *node)
{
/* using lasso_node_impl_dump because dump method can be overrided */
return (lasso_node_impl_dump(node, "utf-8", 0));
}
static xmlChar *
lasso_node_impl_export_to_base64(LassoNode *node)
{
xmlChar *buffer, *ret;
buffer = lasso_node_impl_dump(node, "utf-8", 0);
ret = xmlSecBase64Encode((const xmlSecByte *) buffer,
(xmlSecSize)strlen((const char *)buffer), 0);
xmlFree(buffer);
return (ret);
}
static gchar *
lasso_node_impl_export_to_query(LassoNode *node,
lassoSignatureMethod sign_method,
const gchar *private_key_file)
{
GString *query;
xmlDocPtr doc;
xmlChar *str1, *str2, *str_escaped = NULL;
gchar *unsigned_query, *ret;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
unsigned_query = lasso_node_build_query(node);
query = g_string_new(unsigned_query);
g_free(unsigned_query);
if (sign_method > 0 && private_key_file != NULL) {
/* add SigAlg in query */
query = g_string_append(query, "&SigAlg=");
switch (sign_method) {
case lassoSignatureMethodRsaSha1:
str_escaped = lasso_str_escape((xmlChar *)xmlSecHrefRsaSha1);
break;
case lassoSignatureMethodDsaSha1:
str_escaped = lasso_str_escape((xmlChar *)xmlSecHrefDsaSha1);
break;
}
query = g_string_append(query, str_escaped);
xmlFree(str_escaped);
/* try to sign query */
doc = lasso_str_sign(query->str, sign_method, private_key_file);
if (doc != NULL) {
str1 = lasso_doc_get_node_content(doc, xmlSecNodeSignatureValue);
str2 = lasso_str_escape(str1);
xmlFree(str1);
xmlFreeDoc(doc);
}
else {
g_string_free(query, TRUE);
return (NULL);
}
/* add signature in query */
query = g_string_append(query, "&Signature=");
query = g_string_append(query, str2);
xmlFree(str2);
}
ret = g_strdup(query->str);
g_string_free(query, TRUE);
return (ret);
}
/**
* lasso_node_impl_export_to_soap:
* @node: a LassoNode
*
*
*
* Return value:
**/
static xmlChar *
lasso_node_impl_export_to_soap(LassoNode *node)
{
LassoNode *envelope, *body, *copy_node;
xmlChar *buffer;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
envelope = lasso_node_new();
lasso_node_set_name(envelope, "Envelope");
lasso_node_set_ns(envelope, lassoSoapEnvHRef, lassoSoapEnvPrefix);
copy_node = lasso_node_copy(node);
body = lasso_node_new();
lasso_node_set_name(body, "Body");
lasso_node_set_ns(body, lassoSoapEnvHRef, lassoSoapEnvPrefix);
lasso_node_add_child(body, copy_node, FALSE);
lasso_node_add_child(envelope, body, FALSE);
buffer = lasso_node_export(envelope);
lasso_node_destroy(copy_node);
lasso_node_destroy(body);
lasso_node_destroy(envelope);
return(buffer);
}
static LassoAttr*
lasso_node_impl_get_attr(LassoNode *node,
const xmlChar *name)
{
LassoAttr *prop;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
g_return_val_if_fail (name != NULL, NULL);
prop = node->private->node->properties;
while (prop != NULL) {
if (xmlStrEqual(prop->name, name)) {
return (prop);
}
prop = prop->next;
}
return (NULL);
}
static xmlChar *
lasso_node_impl_get_attr_value(LassoNode *node,
const xmlChar *name,
GError **err)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (err == NULL || *err == NULL, NULL);
xmlChar *value = xmlGetProp(node->private->node, name);
if (value == NULL) {
g_set_error(err, g_quark_from_string("Lasso"),
LASSO_XML_ERROR_ATTR_VALUE_NOTFOUND,
lasso_strerror(LASSO_XML_ERROR_ATTR_VALUE_NOTFOUND),
name, node->private->node->name);
}
return (value);
}
static GPtrArray *
lasso_node_impl_get_attrs(LassoNode *node)
{
GPtrArray *attributes = NULL;
LassoAttr *prop;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
prop = node->private->node->properties;
if (prop != NULL)
attributes = g_ptr_array_new();
while (prop != NULL) {
g_ptr_array_add(attributes, prop);
prop = prop->next;
}
return (attributes);
}
static LassoNode *
lasso_node_impl_get_child(LassoNode *node,
const xmlChar *name,
const xmlChar *href)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
g_return_val_if_fail (name != NULL, NULL);
/* /\* No recurssive version *\/ */
/* xmlNodePtr cur; */
/* cur = node->private->node->children; */
/* while (cur != NULL) { */
/* if(cur->type == XML_ELEMENT_NODE) { */
/* if (xmlStrEqual(cur->name, name)) { */
/* return (lasso_node_new_from_xmlNode(cur)); */
/* } */
/* } */
/* cur = cur->next; */
/* } */
/* return (NULL); */
/* /\* Recurssive version *\/ */
/* xmlNodePtr cur; */
/* LassoNode *ret, *child; */
/* cur = node->private->node; */
/* while (cur != NULL) { */
/* if ((cur->type == XML_ELEMENT_NODE) && xmlStrEqual(cur->name, name)) { */
/* return (lasso_node_new_from_xmlNode(cur)); */
/* } */
/* if (cur->children != NULL) { */
/* child = lasso_node_new_from_xmlNode(cur->children); */
/* ret = lasso_node_get_child(child, name); */
/* if (ret != NULL) { */
/* return (ret); */
/* } */
/* } */
/* cur = cur->next; */
/* } */
/* return (NULL); */
xmlNodePtr child;
if (href != NULL)
child = xmlSecFindNode(node->private->node, name, href);
else {
child = xmlSecFindNode(node->private->node, name, href);
if (child == NULL)
child = xmlSecFindNode(node->private->node, name, lassoLibHRef);
if (child == NULL)
child = xmlSecFindNode(node->private->node, name, lassoSamlAssertionHRef);
if (child == NULL)
child = xmlSecFindNode(node->private->node, name, lassoSamlProtocolHRef);
if (child == NULL)
child = xmlSecFindNode(node->private->node, name, lassoSoapEnvHRef);
if (child == NULL)
child = xmlSecFindNode(node->private->node, name, lassoMetadataHRef);
}
if (child != NULL)
return (lasso_node_new_from_xmlNode(child));
else
return (NULL);
}
static xmlChar *
lasso_node_impl_get_child_content(LassoNode *node,
const xmlChar *name,
const xmlChar *href)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
g_return_val_if_fail (name != NULL, NULL);
LassoNode *child = lasso_node_get_child(node, name, href);
xmlChar *content = NULL;
if (child != NULL) {
content = lasso_node_get_content(child);
lasso_node_destroy(child);
}
return (content);
}
static GPtrArray *
lasso_node_impl_get_children(LassoNode *node)
{
GPtrArray *children = NULL;
xmlNodePtr cur;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
cur = node->private->node->children;
if (cur != NULL)
children = g_ptr_array_new();
while (cur != NULL) {
g_ptr_array_add(children, lasso_node_new_from_xmlNode(cur));
cur = cur->next;
}
return (children);
}
static xmlChar *
lasso_node_impl_get_content(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
return (xmlNodeGetContent(node->private->node));
}
static const xmlChar *
lasso_node_impl_get_name(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
return (node->private->node->name);
}
static void
lasso_node_impl_import(LassoNode *node,
const xmlChar *buffer)
{
xmlDocPtr doc;
xmlNodePtr root;
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (buffer != NULL);
doc = xmlParseMemory(buffer, strlen(buffer));
/* get root element of doc and duplicate it */
root = xmlCopyNode(xmlDocGetRootElement(doc), 1);
lasso_node_set_xmlNode(node, root);
/* free doc */
xmlFreeDoc(doc);
}
static void
lasso_node_impl_import_from_node(LassoNode *node,
LassoNode *imported_node)
{
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (LASSO_IS_NODE(imported_node));
lasso_node_impl_set_xmlNode(node, xmlCopyNode(imported_node->private->node, 1));
}
static void
lasso_node_impl_rename_prop(LassoNode *node,
const xmlChar *old_name,
const xmlChar *new_name)
{
xmlChar *value;
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (old_name != NULL);
g_return_if_fail (new_name != NULL);
value = xmlGetProp(node->private->node, old_name);
if (value != NULL) {
xmlRemoveProp(lasso_node_get_attr(node, old_name));
lasso_node_set_prop(node, new_name, value);
}
}
static gint
lasso_node_impl_verify_signature(LassoNode *node,
const gchar *certificate_file)
{
xmlDocPtr doc = xmlNewDoc("1.0");
xmlNodePtr signature = NULL;
xmlSecKeysMngrPtr mngr = NULL;
xmlSecDSigCtxPtr dsigCtx = NULL;
gint ret = -3;
g_return_val_if_fail (LASSO_IS_NODE(node), -4);
g_return_val_if_fail (certificate_file != NULL, -5);
/* we must associate the xmlNode with an xmlDoc !!! */
xmlAddChild((xmlNodePtr)doc,
LASSO_NODE_GET_CLASS(node)->get_xmlNode(LASSO_NODE(node)));
/* find start node */
signature = xmlSecFindNode(node->private->node, xmlSecNodeSignature,
xmlSecDSigNs);
if (signature == NULL) {
message(G_LOG_LEVEL_ERROR, "Signature element not found.\n");
ret = -2;
goto done;
}
/* create simple keys mngr */
mngr = xmlSecKeysMngrCreate();
if (mngr == NULL) {
message(G_LOG_LEVEL_ERROR, "Failed to create keys manager.\n");
goto done;
}
if (xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
message(G_LOG_LEVEL_ERROR, "Failed to initialize keys manager.\n");
goto done;
}
/* load trusted cert */
if (xmlSecCryptoAppKeysMngrCertLoad(mngr, certificate_file,
xmlSecKeyDataFormatPem,
xmlSecKeyDataTypeTrusted) < 0) {
message(G_LOG_LEVEL_ERROR, "Failed to load pem certificate from \"%s\".\n",
certificate_file);
goto done;
}
/* create signature context */
dsigCtx = xmlSecDSigCtxCreate(mngr);
if (dsigCtx == NULL) {
message(G_LOG_LEVEL_ERROR, "Failed to create signature context.\n");
goto done;
}
/* verify signature */
if (xmlSecDSigCtxVerify(dsigCtx, signature) < 0) {
message(G_LOG_LEVEL_ERROR, "Failed to verify signature.\n");
goto done;
}
if (dsigCtx->status == xmlSecDSigStatusSucceeded) {
ret = 0;
}
else {
message(G_LOG_LEVEL_ERROR, "The signature of response is invalid.\n");
ret = -1;
}
done:
/* cleanup */
if(dsigCtx != NULL) {
xmlSecDSigCtxDestroy(dsigCtx);
}
if(mngr != NULL) {
xmlSecKeysMngrDestroy(mngr);
}
return (ret);
}
/*** private methods **********************************************************/
static void
lasso_node_impl_add_child(LassoNode *node,
LassoNode *child,
gboolean unbounded)
{
xmlNodePtr old_child = NULL;
const xmlChar *href = NULL;
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (LASSO_IS_NODE(child));
/* if child is not unbounded, we search it */
if (!unbounded) {
if (node->private->node->ns != NULL) {
href = node->private->node->ns->href;
}
old_child = xmlSecFindNode(node->private->node,
child->private->node->name,
href);
}
if (!unbounded && old_child != NULL) {
/* child replace old child */
xmlReplaceNode(old_child, child->private->node);
}
else {
/* else child is added */
xmlAddChild(node->private->node, child->private->node);
}
child->private->node_is_weak_ref = TRUE;
}
static gint
lasso_node_impl_add_signature(LassoNode *node,
gint sign_method,
const xmlChar *private_key_file,
const xmlChar *certificate_file)
{
LassoNode *signature = NULL;
gint ret = 0;
switch (sign_method) {
case lassoSignatureMethodRsaSha1:
signature = lasso_ds_signature_new(node, xmlSecTransformRsaSha1Id);
break;
case lassoSignatureMethodDsaSha1:
signature = lasso_ds_signature_new(node, xmlSecTransformDsaSha1Id);
break;
}
lasso_node_add_child(node, signature, TRUE);
ret = lasso_ds_signature_sign(LASSO_DS_SIGNATURE(signature),
private_key_file,
certificate_file);
lasso_node_destroy(signature);
return (ret);
}
static void gdata_build_query_foreach_func(GQuark key_id,
gpointer data,
gpointer user_data) {
guint i;
GString *str;
GPtrArray *array;
array = g_ptr_array_new();
str = g_string_new("");
for (i=0; i<((GPtrArray *)data)->len; i++) {
str = g_string_append(str, g_ptr_array_index((GPtrArray *)data, i));
if (i<((GPtrArray *)data)->len - 1) {
str = g_string_append(str, " ");
}
}
g_ptr_array_add(array, g_strdup((gpointer)g_quark_to_string(key_id)));
g_ptr_array_add(array, str->str);
g_string_free(str, FALSE);
g_ptr_array_add((GPtrArray *)user_data, array);
}
static gchar *
lasso_node_impl_build_query(LassoNode *node)
{
guint i, j;
GData *gd;
GPtrArray *a, *aa;
GString *query;
xmlChar *str_escaped;
gchar *ret;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
gd = lasso_node_serialize(node, NULL);
a = g_ptr_array_new();
/* transform dict into array
each key => [val1, val2, ...] of dict become [key, "val1 val2 ..."] */
g_datalist_foreach(&gd, gdata_build_query_foreach_func, a);
query = g_string_new("");
for (i=0; i<a->len; i++) {
aa = g_ptr_array_index(a, i);
query = g_string_append(query, g_ptr_array_index(aa, 0));
query = g_string_append(query, "=");
str_escaped = lasso_str_escape(g_ptr_array_index(aa, 1));
query = g_string_append(query, str_escaped);
xmlFree(str_escaped);
if (i<a->len - 1) {
query = g_string_append(query, "&");
}
/* free allocated memory for array aa */
for (j=0; j<aa->len; j++) {
g_free(aa->pdata[j]);
}
g_ptr_array_free(aa, TRUE);
}
/* free allocated memory for array a */
g_ptr_array_free(a, TRUE);
g_datalist_clear(&gd);
ret = g_strdup(query->str);
g_string_free(query, TRUE);
return (ret);
}
static xmlNodePtr
lasso_node_impl_get_xmlNode(LassoNode *node)
{
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
return (node->private->node);
}
static void
lasso_node_impl_new_child(LassoNode *node,
const xmlChar *name,
const xmlChar *content,
gboolean unbounded)
{
/* LassoNode *old_child = NULL; */
xmlNodePtr old_child = NULL;
const xmlChar *href = NULL;
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (name != NULL);
g_return_if_fail (content != NULL);
if (!unbounded) {
if (node->private->node->ns != NULL) {
href = node->private->node->ns->href;
}
old_child = xmlSecFindNode(node->private->node, name, href);
/* old_child = lasso_node_get_child(node, name); */
}
if (!unbounded && old_child != NULL) {
/* xmlNodeSetContent(old_child->private->node, content); */
xmlNodeSetContent(old_child, content);
}
else {
xmlNewTextChild(node->private->node, NULL, name, content);
}
}
static void
gdata_serialize_destroy_notify(gpointer data)
{
gint i;
GPtrArray *array = data;
for (i=0; i<array->len; i++) {
xmlFree(array->pdata[i]);
}
g_ptr_array_free(array, TRUE);
}
static GData *
lasso_node_impl_serialize(LassoNode *node,
GData *gd)
{
GPtrArray *attrs, *children;
GPtrArray *values;
const xmlChar *name;
xmlChar *val;
int i;
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
if (gd == NULL) {
g_datalist_init(&gd);
}
attrs = lasso_node_get_attrs(node);
if (attrs != NULL) {
for(i=0; i<attrs->len; i++) {
values = g_ptr_array_new();
name = (xmlChar *)((LassoAttr *)g_ptr_array_index(attrs, i))->name;
/* xmlGetProp returns a COPY of attr value
each val must be xmlFree in gdata_serialize_destroy_notify()
which is called by g_datalist_clear() */
val = xmlGetProp(node->private->node, name);
g_ptr_array_add(values, val);
g_datalist_set_data_full(&gd, name, values, gdata_serialize_destroy_notify);
}
g_ptr_array_free(attrs, TRUE);
}
children = lasso_node_get_children(node);
if (children != NULL) {
for(i=0; i<children->len; i++) {
xmlNodePtr xml_node = ((LassoNode *)g_ptr_array_index(children, i))->private->node;
switch (xml_node->type) {
case XML_ELEMENT_NODE:
gd = lasso_node_serialize(g_ptr_array_index(children, i), gd);
break;
case XML_TEXT_NODE:
name = lasso_node_get_name(node);
/* xmlNodeGetContent returns a COPY of node content
each val must be xmlFree in gdata_serialize_destroy_notify()
which is called by g_datalist_clear() */
val = xmlNodeGetContent(node->private->node);
if (val == NULL)
break;
values = (GPtrArray *)g_datalist_get_data(&gd, name);
if (values == NULL) {
values = g_ptr_array_new();
g_ptr_array_add(values, val);
g_datalist_set_data_full(&gd, name, values,
gdata_serialize_destroy_notify);
}
else {
g_ptr_array_add(values, val);
}
break;
}
lasso_node_destroy((LassoNode *)g_ptr_array_index(children, i));
}
g_ptr_array_free(children, TRUE);
}
return (gd);
}
static void
lasso_node_impl_set_name(LassoNode *node,
const xmlChar *name)
{
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (name != NULL);
xmlNodeSetName(node->private->node, name);
}
static void
lasso_node_impl_set_ns(LassoNode *node,
const xmlChar *href,
const xmlChar *prefix)
{
xmlNsPtr new_ns;
g_return_if_fail (LASSO_IS_NODE(node));
/* href may be NULL */
g_return_if_fail (prefix != NULL);
/* xmlNsPtr cur; */
/* cur = node->private->node->ns; */
/* while (cur != NULL) { */
/* printf("%s:%s\n", cur->prefix, cur->href); */
/* cur = cur->next; */
/* } */
/* cur = node->private->node->nsDef; */
/* while (cur != NULL) { */
/* printf("%s:%s\n", cur->prefix, cur->href); */
/* cur = cur->next; */
/* } */
new_ns = xmlNewNs(node->private->node, href, prefix);
xmlFreeNs(node->private->node->ns);
xmlSetNs(node->private->node, new_ns);
node->private->node->nsDef = new_ns;
}
static void
lasso_node_impl_set_prop(LassoNode *node,
const xmlChar *name,
const xmlChar *value)
{
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (name != NULL);
g_return_if_fail (value != NULL);
xmlSetProp(node->private->node, name, value);
}
static void
lasso_node_impl_set_xmlNode(LassoNode *node,
xmlNodePtr libxml_node)
{
g_return_if_fail (LASSO_IS_NODE(node));
g_return_if_fail (libxml_node != NULL);
xmlFreeNode(node->private->node);
node->private->node = libxml_node;
}
/*****************************************************************************/
/* overrided parent class methods */
/*****************************************************************************/
static void
lasso_node_dispose(LassoNode *node)
{
if (node->private->dispose_has_run) {
return;
}
node->private->dispose_has_run = TRUE;
debug("%s 0x%x disposed ...\n", lasso_node_get_name(node), node);
/* unref reference counted objects */
/* we don't have any here */
parent_class->dispose(G_OBJECT(node));
}
static void
lasso_node_finalize(LassoNode *node)
{
debug("%s 0x%x finalized ...\n", lasso_node_get_name(node), node);
if (node->private->node_is_weak_ref == FALSE) {
xmlUnlinkNode(node->private->node);
xmlFreeNode(node->private->node);
}
g_free (node->private);
parent_class->finalize(G_OBJECT(node));
}
/*****************************************************************************/
/* instance and class init functions */
/*****************************************************************************/
static void
lasso_node_instance_init(LassoNode *instance)
{
LassoNode *node = LASSO_NODE(instance);
node->private = g_new (LassoNodePrivate, 1);
node->private->dispose_has_run = FALSE;
node->private->node_is_weak_ref = FALSE;
node->private->node = xmlNewNode(NULL, "no-name-set");
}
static void
lasso_node_class_init(LassoNodeClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
parent_class = g_type_class_peek_parent(class);
/* virtual public methods */
class->copy = lasso_node_impl_copy;
class->destroy = lasso_node_impl_destroy;
class->dump = lasso_node_impl_dump;
class->export = lasso_node_impl_export;
class->export_to_base64 = lasso_node_impl_export_to_base64;
class->export_to_query = lasso_node_impl_export_to_query;
class->export_to_soap = lasso_node_impl_export_to_soap;
class->get_attr = lasso_node_impl_get_attr;
class->get_attr_value = lasso_node_impl_get_attr_value;
class->get_attrs = lasso_node_impl_get_attrs;
class->get_child = lasso_node_impl_get_child;
class->get_child_content = lasso_node_impl_get_child_content;
class->get_children = lasso_node_impl_get_children;
class->get_content = lasso_node_impl_get_content;
class->get_name = lasso_node_impl_get_name;
class->import = lasso_node_impl_import;
class->import_from_node = lasso_node_impl_import_from_node;
class->rename_prop = lasso_node_impl_rename_prop;
class->verify_signature = lasso_node_impl_verify_signature;
/* virtual private methods */
class->add_child = lasso_node_impl_add_child;
class->add_signature = lasso_node_impl_add_signature;
class->build_query = lasso_node_impl_build_query;
class->get_xmlNode = lasso_node_impl_get_xmlNode;
class->new_child = lasso_node_impl_new_child;
class->serialize = lasso_node_impl_serialize;
class->set_name = lasso_node_impl_set_name;
class->set_ns = lasso_node_impl_set_ns;
class->set_prop = lasso_node_impl_set_prop;
class->set_xmlNode = lasso_node_impl_set_xmlNode;
/* override parent class methods */
gobject_class->dispose = (void *)lasso_node_dispose;
gobject_class->finalize = (void *)lasso_node_finalize;
}
GType lasso_node_get_type() {
static GType this_type = 0;
if (!this_type) {
static const GTypeInfo this_info = {
sizeof (LassoNodeClass),
NULL,
NULL,
(GClassInitFunc) lasso_node_class_init,
NULL,
NULL,
sizeof(LassoNode),
0,
(GInstanceInitFunc) lasso_node_instance_init,
};
this_type = g_type_register_static(G_TYPE_OBJECT , "LassoNode",
&this_info, 0);
}
return this_type;
}
/**
* lasso_node_new:
*
* The main LassoNode constructor.
*
* Return value: a new node
**/
LassoNode*
lasso_node_new()
{
return (LASSO_NODE(g_object_new(LASSO_TYPE_NODE, NULL)));
}
/**
* lasso_node_new_from_dump:
* @buffer: a buffer
*
* Builds a new LassoNode from an LassoNode dump.
*
* Return value: a new node
**/
LassoNode*
lasso_node_new_from_dump(const xmlChar *buffer)
{
LassoNode *node;
xmlDocPtr doc;
xmlNodePtr root;
g_return_val_if_fail (buffer != NULL, NULL);
node = LASSO_NODE(g_object_new(LASSO_TYPE_NODE, NULL));
doc = xmlParseMemory(buffer, strlen(buffer));
/* get root element of doc and duplicate it */
root = xmlCopyNode(xmlDocGetRootElement(doc), 1);
lasso_node_set_xmlNode(node, root);
/* free doc */
xmlFreeDoc(doc);
return (node);
}
/**
* lasso_node_new_from_xmlNode:
* @node: an xmlNode
*
* Builds a new LassoNode from an xmlNode.
*
* Return value: a new node
**/
LassoNode*
lasso_node_new_from_xmlNode(xmlNodePtr node)
{
LassoNode *lasso_node;
g_return_val_if_fail (node != NULL, NULL);
lasso_node = LASSO_NODE(g_object_new(LASSO_TYPE_NODE, NULL));
lasso_node_set_xmlNode(lasso_node, node);
lasso_node->private->node_is_weak_ref = TRUE;
return (lasso_node);
}