Projet

Général

Profil

Bug #12829 » xml.c

Patched xml.c (based on release 2.5.0) - Ivan Krivyakov, 03 août 2016 23:56

 
1
/* $Id$
2
 *
3
 * Lasso - A free implementation of the Liberty Alliance specifications.
4
 *
5
 * Copyright (C) 2004-2007 Entr'ouvert
6
 * http://lasso.entrouvert.org
7
 *
8
 * Authors: See AUTHORS file in top-level directory.
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22
 */
23

    
24
/**
25
 * SECTION:node
26
 * @short_description: Base class for all Lasso objects
27
 *
28
 * #LassoNode is the base class for Lasso objects; just a step over GObject as
29
 * defined in glib.
30
 *
31
 */
32

    
33
#include "private.h"
34
#include <ctype.h>
35
#include <errno.h>
36
#include <string.h>
37

    
38
#include <xmlsec/base64.h>
39
#include <xmlsec/xmltree.h>
40
#include <xmlsec/xmldsig.h>
41
#include <xmlsec/templates.h>
42
#include <xmlsec/crypto.h>
43
#include <xmlsec/xmlenc.h>
44
#include <xmlsec/openssl/crypto.h>
45
#include <xmlsec/openssl/x509.h>
46

    
47
#include "xml.h"
48
#include "xml_enc.h"
49
#include "saml_name_identifier.h"
50
#include "../utils.h"
51
#include "../registry.h"
52
#include "../debug.h"
53
#include "soap-1.1/soap_envelope.h"
54
#include "soap-1.1/soap_body.h"
55
#include "misc_text_node.h"
56
#include "../lasso_config.h"
57
#ifdef LASSO_WSF_ENABLED
58
#include "idwsf_strings.h"
59
#include "id-wsf-2.0/idwsf2_strings.h"
60
#endif
61

    
62
/* Needed for ECP */
63
#include "saml-2.0/samlp2_idp_list.h"
64
#include "paos_request.h"
65
#include "ecp/ecp_request.h"
66
#include "ecp/ecp_response.h"
67
#include "ecp/ecp_relaystate.h"
68

    
69
#include "../key.h"
70

    
71
#define LOG_LEVEL_XML_DEBUG G_LOG_LEVEL_DEBUG /* change to G_LOG_LEVEL_WARNING so it shows in Apache log */
72

    
73
static void lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, xmlNode *xmlnode,
74
		struct XmlSnippet *snippets, gboolean lasso_dump);
75
static struct XmlSnippet* find_xml_snippet_by_name(LassoNode *node, char *name, LassoNodeClass **class_p);
76
static gboolean set_value_at_path(LassoNode *node, char *path, char *query_value);
77
static char* get_value_by_path(LassoNode *node, char *path, struct XmlSnippet *xml_snippet);
78
static gboolean find_path(LassoNode *node, char *path, LassoNode **value_node,
79
		LassoNodeClass **class_p, struct XmlSnippet **snippet);
80

    
81
static void lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
82
		struct XmlSnippet *snippet_signature);
83
static void lasso_node_traversal(LassoNode *node, void (*do_to_node)(LassoNode *node, SnippetType type), SnippetType type);
84

    
85
static LassoNode* lasso_node_new_from_xmlNode_with_type(xmlNode *xmlnode, char *typename);
86
static void lasso_node_remove_original_xmlnode(LassoNode *node, SnippetType type);
87

    
88
GHashTable *dst_services_by_href = NULL; /* ID-WSF 1 extra DST services, indexed on href */
89
GHashTable *dst_services_by_prefix = NULL; /* ID-WSF 1 extra DST services, indexed on prefix */
90

    
91
GHashTable *idwsf2_dst_services_by_href = NULL; /* ID-WSF 2 DST services, indexed on href */
92
GHashTable *idwsf2_dst_services_by_prefix = NULL; /* ID-WSF 2 DST services, indexed on prefix */
93

    
94
/*****************************************************************************/
95
/* global methods                                                            */
96
/*****************************************************************************/
97

    
98
/**
99
 * lasso_register_dst_service:
100
 * @prefix: prefix of DST service
101
 * @href: href of DST service
102
 *
103
 * Registers prefix and href of a custom data service template service.
104
 **/
105
void
106
lasso_register_dst_service(const gchar *prefix, const gchar *href)
107
{
108
	if (dst_services_by_href == NULL) {
109
		dst_services_by_href = g_hash_table_new_full(
110
				g_str_hash, g_str_equal, g_free, g_free);
111
		dst_services_by_prefix = g_hash_table_new_full(
112
				g_str_hash, g_str_equal, g_free, g_free);
113
	}
114
	g_hash_table_insert(dst_services_by_prefix, g_strdup(prefix), g_strdup(href));
115
	g_hash_table_insert(dst_services_by_href, g_strdup(href), g_strdup(prefix));
116
}
117

    
118
void
119
lasso_register_idwsf2_dst_service(const gchar *prefix, const gchar *href)
120
{
121
	if (idwsf2_dst_services_by_href == NULL) {
122
		idwsf2_dst_services_by_href = g_hash_table_new_full(
123
				g_str_hash, g_str_equal, g_free, g_free);
124
		idwsf2_dst_services_by_prefix = g_hash_table_new_full(
125
				g_str_hash, g_str_equal, g_free, g_free);
126
	}
127
	g_hash_table_insert(idwsf2_dst_services_by_prefix, g_strdup(prefix), g_strdup(href));
128
	g_hash_table_insert(idwsf2_dst_services_by_href, g_strdup(href), g_strdup(prefix));
129
}
130

    
131
gchar*
132
lasso_get_prefix_for_dst_service_href(const gchar *href)
133
{
134
	if (dst_services_by_href == NULL)
135
		return NULL;
136

    
137
	return g_strdup(g_hash_table_lookup(dst_services_by_href, href));
138
}
139

    
140
gchar*
141
lasso_get_prefix_for_idwsf2_dst_service_href(const gchar *href)
142
{
143
	if (idwsf2_dst_services_by_href == NULL)
144
		return NULL;
145

    
146
	return g_strdup(g_hash_table_lookup(idwsf2_dst_services_by_href, href));
147
}
148

    
149

    
150
/*****************************************************************************/
151
/* virtual public methods                                                    */
152
/*****************************************************************************/
153

    
154
static char*
155
_lasso_node_export_to_xml(LassoNode *node, gboolean format, gboolean dump, int level)
156
{
157
	xmlNode *xmlnode;
158
	char *ret;
159

    
160
	g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
161

    
162
	xmlnode = lasso_node_get_xmlNode(node, dump);
163
	if (xmlnode == NULL) {
164
		return NULL;
165
	}
166
	ret = lasso_xmlnode_to_string(xmlnode, format, level);
167
	xmlFreeNode(xmlnode);
168

    
169
	return ret;
170
}
171

    
172
/**
173
 * lasso_node_dump:
174
 * @node: a #LassoNode
175
 *
176
 * Dumps @node.  All datas in object are dumped in an XML format.
177
 *
178
 * Return value:(transfer full): a full XML dump of @node.  The string must be freed by the
179
 *     caller.
180
 **/
181
char*
182
lasso_node_dump(LassoNode *node)
183
{
184
	return _lasso_node_export_to_xml(node, FALSE, TRUE, 0);
185
}
186

    
187
/**
188
 * lasso_node_debug:
189
 * @node: a #LassoNode
190
 * @level:(default 10): the indentation depth, i.e. the depth of the last nodes to be indented.
191
 *
192
 * Create a debug dump for @node, it is pretty printed so any contained signature will be
193
 * uncheckable.
194
 *
195
 * Return value:(transfer full): a full indented and so human readable dump of @node. The string must be freed by
196
 * the caller.
197
 */
198
char*
199
lasso_node_debug(LassoNode *node, int level)
200
{
201
	return _lasso_node_export_to_xml(node, TRUE, TRUE, level);
202
}
203

    
204
/**
205
 * lasso_node_destroy:
206
 * @node: a #LassoNode
207
 *
208
 * Destroys the #LassoNode.
209
 **/
210
void
211
lasso_node_destroy(LassoNode *node)
212
{
213
	if (node == NULL) {
214
		return;
215
	}
216
	if (LASSO_IS_NODE(node)) {
217
		LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
218
		class->destroy(node);
219
	}
220
}
221

    
222
/**
223
 * lasso_node_export_to_base64:
224
 * @node: a #LassoNode
225
 *
226
 * Exports @node to a base64-encoded message.
227
 *
228
 * Return value: a base64-encoded export of @node.  The string must be freed by
229
 *      the caller.
230
 **/
231
char*
232
lasso_node_export_to_base64(LassoNode *node)
233
{
234
	char *str;
235
	char *ret;
236

    
237
	g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
238

    
239
	str = lasso_node_export_to_xml(node);
240
	if (str == NULL)
241
		return NULL;
242
	ret = (char*)xmlSecBase64Encode(BAD_CAST str, strlen(str), 0);
243
	lasso_release_string(str);
244
	return ret;
245
}
246

    
247
/**
248
 * lasso_node_export_to_ecp_soap_response:
249
 * @node: a #LassoNode
250
 *
251
 * Exports @node to a ECP SOAP message.
252
 *
253
 * Return value: a ECP SOAP export of @node.  The string must be freed by the
254
 *      caller.
255
 **/
256
char*
257
lasso_node_export_to_ecp_soap_response(LassoNode *node, const char *assertionConsumerURL)
258
{
259
	char *ret = NULL;
260
	LassoNode *ecp_response = NULL;
261
	GList *headers = NULL;
262

    
263
	lasso_return_null_if_fail(LASSO_IS_NODE(node));
264
	lasso_return_null_if_fail(assertionConsumerURL);
265

    
266
	/* Build the soap header elements */
267
	ecp_response = lasso_ecp_response_new(assertionConsumerURL);
268
	goto_cleanup_if_fail(ecp_response);
269
	lasso_list_add_new_gobject(headers, ecp_response);
270

    
271
	/* Create soap envelope and serialize into an xml document */
272
	ret = lasso_node_export_to_soap_with_headers(node, headers);
273

    
274
 cleanup:
275
	lasso_release_list_of_gobjects(headers);
276
	return ret;
277
}
278

    
279
/**
280
 * lasso_node_export_to_paos_request:
281
 * @node: a #LassoNode
282
 *
283
 * Exports @node to a PAOS message.
284
 *
285
 * Deprecated, use lasso_node_export_to_paos_request_full() instead
286
 *
287
 * Return value: a PAOS export of @node.  The string must be freed by the
288
 *      caller.
289
 **/
290
char *
291
lasso_node_export_to_paos_request(LassoNode *node, const char *issuer,
292
		const char *responseConsumerURL, const char *relay_state)
293
{
294
	return lasso_node_export_to_paos_request_full(node, issuer, responseConsumerURL,
295
												  NULL, relay_state, TRUE, NULL, NULL);
296
}
297

    
298
/**
299
 * lasso_node_export_to_paos_request_full:
300
 * @node:
301
 * @issuer:
302
 * @responseConsumerURL:
303
 * @message_id: (allow-none):
304
 * @relay_state: (allow-none):
305
 * @is_passive:
306
 * @provider_name: (allow-none):
307
 * @idp_list: (allow-none):
308
 *
309
 * Creates a new SOAP message. The SOAP headers include a PaosRequst,
310
 * a EcpRequest and optionally a EcpRelayState. The SOAP body contains
311
 * the @node parameters.
312
 *
313
 * Returns: string containing a PAOS request. The string must be freed
314
 * by the caller.
315
 **/
316
char *
317
lasso_node_export_to_paos_request_full(LassoNode *node, const char *issuer,
318
									   const char *responseConsumerURL, const char *message_id,
319
									   const char *relay_state, gboolean is_passive, gchar *provider_name,
320
									   LassoSamlp2IDPList *idp_list)
321
{
322
	char *ret = NULL;
323
	LassoNode *paos_request = NULL;
324
	LassoNode *ecp_request = NULL;
325
	LassoNode *ecp_relaystate = NULL;
326
	GList *headers = NULL;
327

    
328
	lasso_return_null_if_fail(LASSO_IS_NODE(node));
329
	lasso_return_null_if_fail(issuer);
330
	lasso_return_null_if_fail(responseConsumerURL);
331

    
332
	/* Build the soap header elements */
333
	paos_request = lasso_paos_request_new(responseConsumerURL, message_id);
334
	goto_cleanup_if_fail(paos_request);
335
	lasso_list_add_new_gobject(headers, paos_request);
336

    
337
	ecp_request = lasso_ecp_request_new(issuer, is_passive, provider_name, idp_list);
338
	goto_cleanup_if_fail(ecp_request);
339
	lasso_list_add_new_gobject(headers, ecp_request);
340

    
341
	if (relay_state) {
342
		ecp_relaystate = lasso_ecp_relay_state_new(relay_state);
343
		goto_cleanup_if_fail(ecp_relaystate);
344
		lasso_list_add_new_gobject(headers, ecp_relaystate);
345
	}
346

    
347
	/* Create soap envelope and serialize into an xml document */
348
	ret = lasso_node_export_to_soap_with_headers(node, headers);
349

    
350
 cleanup:
351
	lasso_release_list_of_gobjects(headers);
352
	return ret;
353
}
354

    
355
/**
356
 * lasso_node_export_to_query:
357
 * @node: a #LassoNode
358
 * @sign_method:(default 1): the Signature transform method
359
 * @private_key_file:(allow-none): the path to the private key (may be NULL)
360
 *
361
 * Exports @node to a HTTP query string.  If @private_key_file is NULL,
362
 * query won't be signed.
363
 *
364
 * Return value: a HTTP query export of @node.  The string must be freed by the
365
 *      caller.
366
 **/
367
char*
368
lasso_node_export_to_query(LassoNode *node, LassoSignatureMethod sign_method,
369
		const char *private_key_file)
370
{
371
	return lasso_node_export_to_query_with_password(node, sign_method, private_key_file, NULL);
372
}
373

    
374
/**
375
 * lasso_node_export_to_query_with_password:
376
 * @node: a #LassoNode
377
 * @sign_method:(default 1): the Signature transform method
378
 * @private_key_file:(allow-none): the path to the private key (may be NULL)
379
 * @private_key_file_password:(allow-none): the password needed to decrypt the private key
380
 *
381
 * Exports @node to a HTTP query string.  If @private_key_file is NULL,
382
 * query won't be signed.
383
 *
384
 * Return value: a HTTP query export of @node.  The string must be freed by the
385
 *      caller.
386
 **/
387
char*
388
lasso_node_export_to_query_with_password(LassoNode *node,
389
		LassoSignatureMethod sign_method, const char *private_key_file,
390
		const char *private_key_file_password)
391
{
392
	char *unsigned_query, *query = NULL;
393
	LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE;
394

    
395
	g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
396

    
397
	context.signature_method = sign_method;
398
	context.signature_key = lasso_xmlsec_load_private_key(private_key_file,
399
			private_key_file_password, sign_method, NULL);
400

    
401
	if (! context.signature_key) {
402
		return NULL;
403
	}
404

    
405
	unsigned_query = lasso_node_build_query(node);
406
	if (unsigned_query){
407
		query = lasso_query_sign(unsigned_query, context);
408
		if (query) {
409
			lasso_release(unsigned_query);
410
			unsigned_query = query;
411
		}
412
	}
413
	lasso_release_sec_key(context.signature_key);
414
	return unsigned_query;
415
}
416

    
417
/**
418
 * lasso_node_export_to_xml:
419
 * @node: a #LassoNode
420
 *
421
 * Exports @node to an xml message.
422
 *
423
 * Return value: an xml export of @node.  The string must be freed by the
424
 *      caller.
425
 **/
426
gchar*
427
lasso_node_export_to_xml(LassoNode *node)
428
{
429
	return _lasso_node_export_to_xml(node, FALSE, FALSE, 0);
430
}
431

    
432
/**
433
 * lasso_node_export_to_soap:
434
 * @node: a #LassoNode
435
 *
436
 * Exports @node to a SOAP message.
437
 *
438
 * Return value: a SOAP export of @node.  The string must be freed by the
439
 *      caller.
440
 **/
441
char*
442
lasso_node_export_to_soap(LassoNode *node)
443
{
444
	LassoSoapEnvelope *envelope;
445
	LassoSoapBody *body;
446
	char *ret;
447

    
448
	g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
449

    
450
	body = lasso_soap_body_new();
451
	envelope = lasso_soap_envelope_new(body);
452
	lasso_list_add_gobject(body->any, node);
453
	ret = lasso_node_export_to_xml((LassoNode*)envelope);
454
	lasso_release_gobject(envelope);
455
	lasso_release_gobject(body);
456
	return ret;
457
}
458

    
459
/**
460
 * lasso_node_export_to_soap_with_headers:
461
 * @node: a #LassoNode, becomes the SOAP body
462
 * @headers: (allow-none): #GList of #LassNode
463
 *
464
 * Exports @node to a SOAP message. The @node becomes the SOAP body.
465
 * each header in the #headers list is added to the SOAP header if non-NULL.
466
 * @headers is permitted to be an empty list (e.g. NULL).
467
 *
468
 * <example>
469
 * <title>Create SOAP envelope with variable number of header nodes</title>
470
 *
471
 * <para>You need to form a SOAP message with authn_request as the body and
472
 * paos_request, ecp_request and ecp_relaystate as SOAP header elements.
473
 * It is possible one or more of these may be NULL and should be skipped.</para>
474
 * <programlisting>
475
 * char *text = NULL;
476
 * LassoNode *paos_request = NULL;
477
 * LassoNode *ecp_request = NULL;
478
 * LassoNode *ecp_relaystate = NULL;
479
 * GList *headers = NULL;
480
 *
481
 * paos_request = lasso_paos_request_new(responseConsumerURL, message_id);
482
 * ecp_request = lasso_ecp_request_new(issuer, is_passive, provider_name, idp_list);
483
 *
484
 * lasso_list_add_new_gobject(headers, paos_request);
485
 * lasso_list_add_new_gobject(headers, ecp_request);
486
 * lasso_list_add_new_gobject(headers, ecp_relaystate);
487
 *
488
 * text = lasso_node_export_to_soap_with_headers(node, headers);
489
 *
490
 * lasso_release_list_of_gobjects(headers);
491
 * </programlisting>
492
 * </example>
493
 *
494
 * Return value: a SOAP export of @node.  The string must be freed by the
495
 *      caller.
496
 **/
497
char*
498
lasso_node_export_to_soap_with_headers(LassoNode *node, GList *headers)
499
{
500
	GList *i;
501
	LassoSoapEnvelope *envelope = NULL;
502
	LassoNode *header = NULL;
503
	char *ret = NULL;
504

    
505
	g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
506

    
507
	envelope = lasso_soap_envelope_new_full();
508
	lasso_list_add_gobject(envelope->Body->any, node);
509

    
510
	lasso_foreach(i, headers) {
511
		header = i->data;
512
		if (!header) continue;
513

    
514
		goto_cleanup_if_fail(LASSO_IS_NODE(header));
515
		lasso_list_add_gobject(envelope->Header->Other, header); /* adds ref */
516
	}
517

    
518
	ret = lasso_node_export_to_xml((LassoNode*)envelope);
519

    
520
 cleanup:
521
	lasso_release_gobject(envelope);
522
	return ret;
523
}
524

    
525
/**
526
 * lasso_node_encrypt:
527
 * @lasso_node: a #LassoNode to encrypt
528
 * @encryption_public_key : RSA public key the node will be encrypted with
529
 *
530
 * Generate a DES key and encrypt it with the RSA key.
531
 * Then encrypt @lasso_node with the DES key.
532
 *
533
 * Return value: an xmlNode which is the @node in an encrypted fashion.
534
 * It must be freed by the caller.
535
 **/
536
LassoSaml2EncryptedElement*
537
lasso_node_encrypt(LassoNode *lasso_node, xmlSecKey *encryption_public_key,
538
		LassoEncryptionSymKeyType encryption_sym_key_type, const char *recipient)
539
{
540
	xmlDocPtr doc = NULL;
541
	xmlNodePtr orig_node = NULL;
542
	LassoSaml2EncryptedElement *encrypted_element = NULL, *ret = NULL;
543
	xmlSecKeysMngrPtr key_manager = NULL;
544
	xmlNodePtr key_info_node = NULL;
545
	xmlNodePtr encrypted_key_node = NULL;
546
	xmlNodePtr encrypted_data = NULL;
547
	xmlNodePtr key_info_node2 = NULL;
548
	xmlSecEncCtxPtr enc_ctx = NULL;
549
	xmlSecTransformId xmlsec_encryption_sym_key_type;
550
	xmlSecKey *duplicate = NULL;
551

    
552
	if (encryption_public_key == NULL || !xmlSecKeyIsValid(encryption_public_key)) {
553
		message(G_LOG_LEVEL_WARNING, "Invalid encryption key");
554
		goto cleanup;
555
	}
556

    
557
	/* Create a document to contain the node to encrypt */
558
	doc = xmlNewDoc((xmlChar*)"1.0");
559
	orig_node = lasso_node_get_xmlNode(lasso_node, FALSE);
560
	xmlDocSetRootElement(doc, orig_node);
561

    
562
	/* Get the symetric key type */
563
	switch (encryption_sym_key_type) {
564
		case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_256:
565
			xmlsec_encryption_sym_key_type = xmlSecTransformAes256CbcId;
566
			break;
567
		case LASSO_ENCRYPTION_SYM_KEY_TYPE_3DES:
568
			xmlsec_encryption_sym_key_type = xmlSecTransformDes3CbcId;
569
			break;
570
		case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_128:
571
		default:
572
			xmlsec_encryption_sym_key_type = xmlSecTransformAes128CbcId;
573
			break;
574
	}
575

    
576
	/* Create encryption template for a specific symetric key type */
577
	/* saml-core 2.2.4 line 498:
578
	 * The Type attribute SHOULD be present and, if present, MUST contain a value of
579
	 * http://www.w3.org/2001/04/xmlenc#Element. */
580
	encrypted_data = xmlSecTmplEncDataCreate(doc,
581
			xmlsec_encryption_sym_key_type,	NULL, xmlSecTypeEncElement, NULL, NULL);
582

    
583
	if (encrypted_data == NULL) {
584
		message(G_LOG_LEVEL_WARNING, "Failed to create encryption template");
585
		goto cleanup;
586
	}
587

    
588
	if (xmlSecTmplEncDataEnsureCipherValue(encrypted_data) == NULL) {
589
		message(G_LOG_LEVEL_WARNING, "Failed to add CipherValue node");
590
		goto cleanup;
591
	}
592

    
593
	/* create and initialize keys manager, we use a simple list based
594
	 * keys manager, implement your own xmlSecKeysStore klass if you need
595
	 * something more sophisticated
596
	 */
597
	key_manager = xmlSecKeysMngrCreate();
598
	if (key_manager == NULL) {
599
		message(G_LOG_LEVEL_WARNING, "Failed to create keys manager");
600
		goto cleanup;
601
	}
602

    
603
	if (xmlSecCryptoAppDefaultKeysMngrInit(key_manager) < 0) {
604
		message(G_LOG_LEVEL_WARNING, "Failed to initialize keys manager");
605
		goto cleanup;
606
	}
607

    
608
	/* add key to keys manager, from now on keys manager is responsible
609
	 * for destroying key
610
	 */
611
	duplicate = xmlSecKeyDuplicate(encryption_public_key);
612
	if (xmlSecCryptoAppDefaultKeysMngrAdoptKey(key_manager, duplicate) < 0) {
613
		lasso_release_sec_key(duplicate);
614
		goto cleanup;
615
	}
616

    
617
	/* add <dsig:KeyInfo/> */
618
	key_info_node = xmlSecTmplEncDataEnsureKeyInfo(encrypted_data, NULL);
619
	if (key_info_node == NULL) {
620
		message(G_LOG_LEVEL_WARNING, "Failed to add key info");
621
		goto cleanup;
622
	}
623

    
624
	/* add <enc:EncryptedKey/> to store the encrypted session key */
625
	encrypted_key_node = xmlSecTmplKeyInfoAddEncryptedKey(key_info_node,
626
			xmlSecTransformRsaPkcs1Id, NULL, NULL, (xmlChar*)recipient);
627
	if (encrypted_key_node == NULL) {
628
		message(G_LOG_LEVEL_WARNING, "Failed to add encrypted key");
629
		goto cleanup;
630
	}
631

    
632
	/* we want to put encrypted key in the <enc:CipherValue/> node */
633
	if (xmlSecTmplEncDataEnsureCipherValue(encrypted_key_node) == NULL) {
634
		message(G_LOG_LEVEL_WARNING, "Failed to add CipherValue node");
635
		goto cleanup;
636
	}
637

    
638
	/* add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/> */
639
	key_info_node2 = xmlSecTmplEncDataEnsureKeyInfo(encrypted_key_node, NULL);
640
	if (key_info_node2 == NULL) {
641
		message(G_LOG_LEVEL_WARNING, "Failed to add key info");
642
		goto cleanup;
643
	}
644
	/* check id of the key */
645
	if (xmlSecKeyGetData(encryption_public_key, xmlSecOpenSSLKeyDataRsaId) != 0) {
646
		xmlNode *key_value = xmlSecTmplKeyInfoAddKeyValue(key_info_node2);
647
		if (key_value == NULL) {
648
			message(G_LOG_LEVEL_WARNING, "Failed to add key value");
649
			goto cleanup;
650
		}
651
	} else { /* it must be a certificate */
652
		xmlNodePtr x509_data;
653
		x509_data = xmlSecTmplKeyInfoAddX509Data(key_info_node2);
654
		if (x509_data == NULL) {
655
			message(G_LOG_LEVEL_WARNING, "Failed to add X509 data");
656
			goto cleanup;
657
		}
658
	}
659

    
660

    
661

    
662

    
663
	/* create encryption context */
664
	enc_ctx = (xmlSecEncCtxPtr)xmlSecEncCtxCreate(key_manager);
665
	if (enc_ctx == NULL) {
666
		message(G_LOG_LEVEL_WARNING, "Failed to create encryption context");
667
		goto cleanup;
668
	}
669

    
670
	/* generate a symetric key */
671
	switch (encryption_sym_key_type) {
672
		case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_256:
673
			enc_ctx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 256,
674
					xmlSecKeyDataTypeSession);
675
			break;
676
		case LASSO_ENCRYPTION_SYM_KEY_TYPE_3DES:
677
			enc_ctx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192,
678
					xmlSecKeyDataTypeSession);
679
			break;
680
		case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_128:
681
		default:
682
			enc_ctx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 128,
683
					xmlSecKeyDataTypeSession);
684
			break;
685
	}
686

    
687
	if (enc_ctx->encKey == NULL) {
688
		message(G_LOG_LEVEL_WARNING, "Failed to generate session des key");
689
		goto cleanup;
690
	}
691

    
692

    
693
	/* encrypt the data */
694
	if (xmlSecEncCtxXmlEncrypt(enc_ctx, encrypted_data, orig_node) < 0) {
695
		message(G_LOG_LEVEL_WARNING, "Encryption failed");
696
		goto cleanup;
697
	}
698

    
699

    
700
	/* Create a new EncryptedElement */
701
	encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_saml2_encrypted_element_new());
702
	lasso_assign_gobject(encrypted_element->original_data, lasso_node);
703
	lasso_assign_xml_node(encrypted_element->EncryptedData, xmlDocGetRootElement(doc));
704
	lasso_transfer_gobject(ret, encrypted_element);
705

    
706
cleanup:
707
	lasso_release_key_manager(key_manager);
708
	lasso_release_gobject(encrypted_element);
709
	lasso_release_encrypt_context(enc_ctx);
710
	lasso_release_doc(doc);
711

    
712
	return ret;
713
}
714

    
715

    
716
/**
717
 * lasso_node_init_from_query:
718
 * @node: a #LassoNode (or derived class)
719
 * @query: the query string
720
 *
721
 * Initialiazes @node fields with data from @query string.
722
 *
723
 * Return value: %TRUE if success
724
 **/
725
gboolean
726
lasso_node_init_from_query(LassoNode *node, const char *query)
727
{
728
	LassoNodeClass *class;
729
	char **query_fields;
730
	int i;
731
	gboolean rc;
732

    
733
	g_return_val_if_fail(LASSO_IS_NODE(node), FALSE);
734
	class = LASSO_NODE_GET_CLASS(node);
735

    
736
	query_fields = urlencoded_to_strings(query);
737
	rc = class->init_from_query(node, query_fields);
738
	for (i = 0; query_fields[i]; i++) {
739
		xmlFree(query_fields[i]);
740
		query_fields[i] = NULL;
741
	}
742
	lasso_release(query_fields);
743
	return rc;
744
}
745

    
746

    
747
/**
748
 * lasso_node_init_from_xml:
749
 * @node: a #LassoNode (or derived class)
750
 * @xmlnode: the libxml2 node
751
 *
752
 * Initialiazes @node fields with data from @xmlnode XML node.
753
 *
754
 * Return value: 0 on success; or a negative value otherwise.
755
 **/
756
int
757
lasso_node_init_from_xml(LassoNode *node, xmlNode *xmlnode)
758
{
759
	LassoNodeClass *class;
760

    
761
	g_return_val_if_fail(LASSO_IS_NODE(node), LASSO_XML_ERROR_OBJECT_CONSTRUCTION_FAILED);
762
	class = LASSO_NODE_GET_CLASS(node);
763

    
764
	return class->init_from_xml(node, xmlnode);
765
}
766

    
767
/**
768
 * lasso_node_build_query:
769
 * @node: a #LassoNode
770
 *
771
 * Build an HTTP query from the given LassoNode, this is a pure virtual
772
 * function, you must overload it in subclass.
773
 *
774
 * Return value: a newly allocated string containing the query if it succeed,
775
 * or NULL otherwise.
776
 */
777
char*
778
lasso_node_build_query(LassoNode *node)
779
{
780
	LassoNodeClass *class;
781
	g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
782

    
783
	class = LASSO_NODE_GET_CLASS(node);
784
	return class->build_query(node);
785
}
786

    
787
static LassoNodeClassData*
788
lasso_legacy_get_signature_node_data(LassoNode *node, LassoNodeClass **out_klass)
789
{
790
	LassoNodeClass *klass = NULL;
791
	LassoNodeClassData *node_data = NULL;
792

    
793
	klass = LASSO_NODE_GET_CLASS(node);
794
	/* find a klass defining a signature */
795
	while (klass && LASSO_IS_NODE_CLASS(klass)) {
796
		if (klass->node_data && klass->node_data->sign_type_offset) {
797
			if (out_klass) {
798
				*out_klass = klass;
799
			}
800
			node_data = klass->node_data;
801
			break;
802
		}
803
		klass = g_type_class_peek_parent(klass);
804
	}
805

    
806
	return node_data;
807
}
808

    
809
static gboolean
810
lasso_legacy_extract_and_copy_signature_parameters(LassoNode *node, LassoNodeClassData *node_data)
811
{
812
	LassoSignatureMethod signature_method = LASSO_SIGNATURE_METHOD_NONE;
813
	char *private_key_file = NULL;
814
	char *certificate_file = NULL;
815

    
816
	if (! node_data) {
817
		return FALSE;
818
	}
819
	signature_method = G_STRUCT_MEMBER(LassoSignatureMethod, node,
820
			node_data->sign_method_offset);
821
	private_key_file = G_STRUCT_MEMBER(char *, node, node_data->private_key_file_offset);
822
	certificate_file = G_STRUCT_MEMBER(char *, node, node_data->certificate_file_offset);
823
	if (! lasso_validate_signature_method(signature_method)) {
824
		return FALSE;
825
	}
826
	if (lasso_node_set_signature(node,
827
			lasso_make_signature_context_from_path_or_string(private_key_file, NULL,
828
				signature_method, certificate_file)) != 0) {
829
		return FALSE;
830
	}
831
	return TRUE;
832
}
833

    
834
/**
835
 * lasso_node_get_xmlNode:
836
 * @node: a #LassoNode
837
 * @lasso_dump: whether to include lasso-specific nodes
838
 *
839
 * Builds an XML representation of @node.
840
 *
841
 * Return value: a new xmlNode.  It must be freed by the caller.
842
 **/
843
xmlNode*
844
lasso_node_get_xmlNode(LassoNode *node, gboolean lasso_dump)
845
{
846
	xmlNode *xmlnode = NULL;
847
	LassoSignatureContext context;
848
	LassoNodeClassData *node_data;
849

    
850
	g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
851
	xmlnode = LASSO_NODE_GET_CLASS(node)->get_xmlNode(node, lasso_dump);
852
	node_data = lasso_legacy_get_signature_node_data(node, NULL);
853
	context = lasso_node_get_signature(node);
854
	/* support for legacy way to put a signature on a node */
855
	if (! lasso_validate_signature_context(context)) {
856
		if (lasso_legacy_extract_and_copy_signature_parameters(node, node_data))
857
			context = lasso_node_get_signature(node);
858
	}
859
	if (! lasso_dump && node_data && xmlnode && lasso_validate_signature_context(context)) {
860
		int rc;
861
		char *id_attribute = G_STRUCT_MEMBER(char*, node,
862
				node_data->id_attribute_offset);
863

    
864
		rc = lasso_sign_node(xmlnode, context, node_data->id_attribute_name,
865
				id_attribute);
866
		if (rc != 0) {
867
			warning("Signing of %s:%s failed: %s", xmlnode->ns->prefix,
868
					xmlnode->name, lasso_strerror(rc));
869
			lasso_release_xml_node(xmlnode);
870
		}
871
	}
872

    
873
	return xmlnode;
874
}
875

    
876
/**
877
 * lasso_node_cleanup_original_xmlnodes:
878
 *
879
 * @node: a #LassoNode
880
 *
881
 * Traverse the #LassoNode tree starting at Node and remove keeped xmlNode if one is found.
882
 *
883
 * Return value: None
884
 */
885
void
886
lasso_node_cleanup_original_xmlnodes(LassoNode *node)
887
{
888
	lasso_node_traversal(node, lasso_node_remove_original_xmlnode, 0);
889
}
890

    
891
static GQuark original_xmlnode_quark;
892
static GQuark custom_element_quark;
893

    
894
/**
895
 * lasso_node_get_original_xmlnode:
896
 * @node: a #LassoNode
897
 *
898
 * Retrieve the original xmlNode eventually associated to this #LassoNode.
899
 *
900
 * Return value:(transfer none): an #xmlNodePtr or NULL.
901
 */
902
xmlNodePtr
903
lasso_node_get_original_xmlnode(LassoNode *node)
904
{
905
	return g_object_get_qdata(G_OBJECT(node), original_xmlnode_quark);
906
}
907

    
908
static void original_xmlnode_free(void *node) {
909
	xmlNode *xnode = (xmlNode*)node;
910

    
911

    
912
	if (node) {
913
		if (lasso_flag_memory_debug) {
914
			fprintf(stderr, "freeing original xmlnode %s (at %p)\n", xnode->name, xnode);
915
		}
916
		xmlFreeNode(xnode);
917
	}
918
}
919

    
920
/**
921
 * lasso_node_set_original_xmlnode:
922
 * @node: the #LassoNode object
923
 * @xmlnode: an #xmlNode
924
 *
925
 * Set the underlying XML representation of the object.
926
 *
927
 */
928
void
929
lasso_node_set_original_xmlnode(LassoNode *node, xmlNode* xmlnode)
930
{
931
	if (xmlnode) {
932
		xmlNode *copy = NULL;
933
		xmlNode *parent = xmlnode->parent;
934

    
935
		copy = xmlCopyNode(xmlnode, 1);
936
		/* excl-c14n can move some namespace declarations at the point where the document is
937
		 * cut, to simulate it we copy on the new node all namespaces from the parents of
938
		 * the node which are not shadowed by another declaration on this node or one of its
939
		 * parent. */
940
		while (parent && parent->type == XML_ELEMENT_NODE) {
941
			xmlNs *ns_def = parent->nsDef;
942
			xmlNs *local_ns_def;
943
			while (ns_def) {
944
				int ok = 1;
945
				local_ns_def = copy->nsDef;
946
				while (local_ns_def) {
947
					if (lasso_strisequal((char*)local_ns_def->prefix, (char*)ns_def->prefix)) {
948
						ok = 0;
949
						break;
950
					}
951
					local_ns_def = local_ns_def->next;
952
				}
953
				if (ok) {
954
					xmlNewNs(copy, ns_def->href, ns_def->prefix);
955
				}
956
				ns_def = ns_def->next;
957
			}
958
			parent = parent->parent;
959
		}
960

    
961
		if (lasso_flag_memory_debug) {
962
			fprintf(stderr, "setting original xmlnode (at %p) on node %s:%p\n", copy, G_OBJECT_TYPE_NAME (node), node);
963
		}
964
		g_object_set_qdata_full(G_OBJECT(node), original_xmlnode_quark, copy, (GDestroyNotify)original_xmlnode_free);
965
	} else {
966
		if (lasso_flag_memory_debug) {
967
			fprintf(stderr, "clearing original xmlnode on node %p\n", node);
968
		}
969
		g_object_set_qdata_full(G_OBJECT(node), original_xmlnode_quark, NULL, (GDestroyNotify)original_xmlnode_free);
970
	}
971
}
972

    
973
struct _CustomElement {
974
	char *prefix;
975
	char *href;
976
	char *nodename;
977
	GHashTable *namespaces;
978
	LassoSignatureContext signature_context;
979
	xmlSecKey *encryption_public_key;
980
	LassoEncryptionSymKeyType encryption_sym_key_type;
981
};
982

    
983
static struct _CustomElement *
984
_lasso_node_new_custom_element()
985
{
986
	struct _CustomElement *ret = g_new0(struct _CustomElement, 1);
987
	ret->namespaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
988
	return ret;
989
}
990

    
991
static void
992
_lasso_node_free_custom_element(struct _CustomElement *custom_element)
993
{
994
	if (custom_element) {
995
		lasso_release_string(custom_element->prefix);
996
		lasso_release_string(custom_element->href);
997
		lasso_release_string(custom_element->nodename);
998
		lasso_release_ghashtable(custom_element->namespaces);
999
		lasso_release_sec_key(custom_element->encryption_public_key);
1000
		lasso_release_sec_key(custom_element->signature_context.signature_key);
1001
	}
1002
	lasso_release(custom_element);
1003
}
1004

    
1005
/**
1006
 * _lasso_node_get_custom_element:
1007
 * @node: a #LassoNode object
1008
 *
1009
 * Return the eventually attached custom namespace object
1010
 *
1011
 * Return value: NULL or an #_CustomElement structure.
1012
 */
1013
static struct _CustomElement*
1014
_lasso_node_get_custom_element(LassoNode *node)
1015
{
1016
	if (! LASSO_NODE(node))
1017
		return NULL;
1018
	return g_object_get_qdata((GObject*)node, custom_element_quark);
1019
}
1020

    
1021
static struct _CustomElement*
1022
_lasso_node_get_custom_element_or_create(LassoNode *node)
1023
{
1024
	struct _CustomElement *custom_element;
1025

    
1026
	if (! LASSO_IS_NODE(node))
1027
		return NULL;
1028

    
1029
	custom_element = _lasso_node_get_custom_element(node);
1030
	if (! custom_element) {
1031
		custom_element = _lasso_node_new_custom_element();
1032
		g_object_set_qdata_full((GObject*)node, custom_element_quark,
1033
				custom_element,
1034
				(GDestroyNotify)_lasso_node_free_custom_element);
1035
	}
1036
	return custom_element;
1037
}
1038

    
1039

    
1040
/**
1041
 * lasso_node_set_custom_namespace:
1042
 * @node: a #LassoNode object
1043
 * @prefix: the prefix to use for the definition
1044
 * @href: the URI of the namespace
1045
 *
1046
 * Set a custom namespace for an object instance, use it with object existing a lot of revision of
1047
 * the nearly same namespace.
1048
 */
1049
void
1050
lasso_node_set_custom_namespace(LassoNode *node, const char *prefix, const char *href)
1051
{
1052
	struct _CustomElement *custom_element;
1053

    
1054
	custom_element = _lasso_node_get_custom_element_or_create(node);
1055
	g_return_if_fail (custom_element != NULL);
1056

    
1057
	lasso_assign_string(custom_element->prefix, prefix);
1058
	lasso_assign_string(custom_element->href, href);
1059
}
1060

    
1061
/**
1062
 * lasso_node_set_signature:
1063
 * @node: a #LassoNode object
1064
 * @signature_context: a #LassoSignatureContext structure
1065
 *
1066
 * Setup a signature on @node.
1067
 *
1068
 * Return value: 0 if successful, an error code otherwise.
1069
 */
1070
int
1071
lasso_node_set_signature(LassoNode *node, LassoSignatureContext context)
1072
{
1073
	struct _CustomElement *custom_element;
1074
	int rc = 0;
1075

    
1076
	lasso_bad_param(NODE, node);
1077
	custom_element = _lasso_node_get_custom_element_or_create(node);
1078
	g_return_val_if_fail (custom_element != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1079

    
1080
	if (custom_element->signature_context.signature_key) {
1081
		lasso_release_sec_key(custom_element->signature_context.signature_key);
1082
	}
1083
	custom_element->signature_context.signature_method = context.signature_method;
1084
	lasso_assign_new_sec_key(custom_element->signature_context.signature_key,
1085
			context.signature_key);
1086
	return rc;
1087
}
1088

    
1089
/**
1090
 * lasso_node_get_signature:
1091
 * @node: a #LassoNode object
1092
 * @type: an output for the signature type
1093
 * @method: an output for the signature method
1094
 * @private_key: an output for the private key
1095
 * @private_key_password: an output for the private key password
1096
 * @certificate: an output for the certificate
1097
 *
1098
 * Return signature parameters stored with this node.
1099
 */
1100
LassoSignatureContext
1101
lasso_node_get_signature(LassoNode *node)
1102
{
1103
	struct _CustomElement *custom_element;
1104

    
1105
	g_return_val_if_fail (LASSO_IS_NODE(node), LASSO_SIGNATURE_CONTEXT_NONE);
1106
	custom_element = _lasso_node_get_custom_element(node);
1107
	if (! custom_element) {
1108
		return LASSO_SIGNATURE_CONTEXT_NONE;
1109
	}
1110
	return custom_element->signature_context;
1111
}
1112

    
1113
/**
1114
 * lasso_node_set_encryption:
1115
 * @node: a @LassoNode object
1116
 * @encryption_public_key: an #xmlSecKey used to crypt the session key
1117
 * @encryption_sym_key_type: the kind of session key to use
1118
 *
1119
 * Setup a node for future encryption. It is read by saml2:EncryptedElement for eventually
1120
 * encrypting nodes.
1121
 *
1122
 * Return value: 0 if successful, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if node is not a
1123
 * #LassoNode.
1124
 */
1125
void
1126
lasso_node_set_encryption(LassoNode *node, xmlSecKey *encryption_public_key,
1127
		LassoEncryptionSymKeyType encryption_sym_key_type)
1128
{
1129
	struct _CustomElement *custom_element;
1130

    
1131
	g_return_if_fail(LASSO_IS_NODE(node));
1132
	if (encryption_public_key) {
1133
		custom_element = _lasso_node_get_custom_element_or_create(node);
1134
		if (! custom_element) {
1135
			return;
1136
		}
1137
	} else {
1138
		custom_element = _lasso_node_get_custom_element(node);
1139
		if (! custom_element) {
1140
			return;
1141
		}
1142
		lasso_release_sec_key(custom_element->encryption_public_key);
1143
		return;
1144
	}
1145
	lasso_assign_sec_key(custom_element->encryption_public_key,
1146
			encryption_public_key);
1147
	if (encryption_sym_key_type < LASSO_ENCRYTPION_SYM_KEY_TYPE_LAST) {
1148
		custom_element->encryption_sym_key_type = encryption_sym_key_type;
1149
	} else {
1150
		custom_element->encryption_sym_key_type = LASSO_ENCRYPTION_SYM_KEY_TYPE_DEFAULT;
1151
	}
1152
}
1153

    
1154
/**
1155
 * lasso_node_get_encryption:
1156
 * @node: a #LassoNode object
1157
 * @encryption_public_key_ptr: a pointer on a pointer to an #xmlSecKey object, to hold the the
1158
 * public key used to encrypt the session key
1159
 * @encryption_sym_key_type: a pointer on a #LassoEncryptionSymKeyType
1160
 *
1161
 * Lookup eventual configuration for encrypting the given node.
1162
 */
1163
void
1164
lasso_node_get_encryption(LassoNode *node, xmlSecKey **encryption_public_key,
1165
		LassoEncryptionSymKeyType *encryption_sym_key_type)
1166
{
1167
	struct _CustomElement *custom_element;
1168

    
1169
	g_return_if_fail(LASSO_IS_NODE(node));
1170
	custom_element = _lasso_node_get_custom_element(node);
1171
	if (custom_element && custom_element->encryption_public_key) {
1172
		lasso_assign_sec_key(*encryption_public_key,
1173
				custom_element->encryption_public_key);
1174
		*encryption_sym_key_type = custom_element->encryption_sym_key_type;
1175
	}
1176
}
1177

    
1178
/**
1179
 * lasso_node_set_custom_nodename:
1180
 * @node: a #LassoNode object
1181
 * @nodename: the name to use for the node
1182
 *
1183
 * Set a custom nodename for an object instance, use it with object implement a schema type and not
1184
 * a real element.
1185
 */
1186
void
1187
lasso_node_set_custom_nodename(LassoNode *node, const char *nodename)
1188
{
1189
	struct _CustomElement *custom_element;
1190

    
1191
	custom_element = _lasso_node_get_custom_element_or_create(node);
1192
	g_return_if_fail (custom_element != NULL);
1193

    
1194
	lasso_assign_string(custom_element->nodename, nodename);
1195
}
1196

    
1197
/**
1198
 * lasso_node_add_custom_namespace:
1199
 * @prefix: prefix name
1200
 * @href: href url
1201
 *
1202
 * Add a custom namespace declaration at this node level
1203
 */
1204
void
1205
lasso_node_add_custom_namespace(LassoNode *node, const char *prefix,
1206
		const char *href)
1207
{
1208
	struct _CustomElement *custom_element;
1209

    
1210
	custom_element = _lasso_node_get_custom_element_or_create(node);
1211
	g_return_if_fail(custom_element != NULL);
1212

    
1213
	g_hash_table_insert(custom_element->namespaces, g_strdup(prefix), g_strdup(href));
1214
}
1215

    
1216
/*****************************************************************************/
1217
/* implementation methods                                                    */
1218
/*****************************************************************************/
1219

    
1220
static void
1221
lasso_node_remove_original_xmlnode(LassoNode *node, SnippetType type) {
1222
	LassoNodeClass *class;
1223
	class = LASSO_NODE_GET_CLASS(node);
1224

    
1225
	if (class->node_data->keep_xmlnode || type & SNIPPET_KEEP_XMLNODE) {
1226
		lasso_node_set_original_xmlnode(node, NULL);
1227
	}
1228
}
1229

    
1230
static void
1231
lasso_node_traversal(LassoNode *node, void (*do_to_node)(LassoNode *node, SnippetType type), SnippetType type) {
1232
	LassoNodeClass *class;
1233
	struct XmlSnippet *snippet;
1234

    
1235
	if (node == NULL || do_to_node == NULL) {
1236
		return;
1237
	}
1238
	class = LASSO_NODE_GET_CLASS(node);
1239
	do_to_node(node, type);
1240

    
1241
	while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
1242
		GType g_type = G_TYPE_FROM_CLASS(class);
1243
		snippet = class->node_data->snippets;
1244
		while (snippet->name != NULL) {
1245
			SnippetType type;
1246
			void **value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
1247

    
1248
			type = snippet->type & 0xff;
1249
			switch (type) {
1250
				case SNIPPET_NODE:
1251
				case SNIPPET_NODE_IN_CHILD:
1252
					lasso_node_traversal(*value, do_to_node, snippet->type);
1253
					break;
1254
				case SNIPPET_LIST_NODES:
1255
					{
1256
						GList *list = *value;
1257
						while (list != NULL) {
1258
							if (list->data) {
1259
								lasso_node_traversal(LASSO_NODE(list->data), do_to_node, snippet->type);
1260
							}
1261
							list = g_list_next(list);
1262
						}
1263
					}
1264
					break;
1265
				case SNIPPET_UNUSED1:
1266
					g_assert_not_reached();
1267
				default:
1268
					break;
1269
			}
1270
			snippet++;
1271
		}
1272
		class = g_type_class_peek_parent(class);
1273
	}
1274
}
1275

    
1276
static void
1277
lasso_node_impl_destroy(LassoNode *node)
1278
{
1279
	g_object_unref(G_OBJECT(node));
1280
}
1281
#define trace_snippet(format, args...) \
1282
	lasso_trace(format "%s.%s\n", ## args, G_OBJECT_TYPE_NAME(node), snippet->name)
1283

    
1284
/**
1285
 * _lasso_node_collect_namespaces:
1286
 * @namespaces: a pointer to a pointer on a #GHashTable
1287
 * @node: an #xmlNode pointer
1288
 *
1289
 * Follow the parent link of the @node to collect all declared namespaces, it is usefull for content
1290
 * that need to be interpreted with respect to declared namespaces (XPath for example).
1291
 */
1292
void
1293
_lasso_node_collect_namespaces(GHashTable **namespaces, xmlNode *node)
1294
{
1295
	if (*namespaces == NULL) {
1296
		*namespaces = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free);
1297
	}
1298
	while (node) {
1299
		if (node->type == XML_ELEMENT_NODE) {
1300
			xmlNs *nsDef = node->nsDef;
1301
			while (nsDef) {
1302
				if (nsDef->prefix && nsDef->href) {
1303
					g_hash_table_insert(*namespaces, g_strdup((char*)nsDef->prefix),
1304
							g_strdup((char*)nsDef->href));
1305
				}
1306
				nsDef = nsDef->next;
1307
			}
1308
		}
1309
		node = node->parent;
1310
	}
1311
}
1312

    
1313
gboolean
1314
lasso_get_integer_attribute(xmlNode *node, xmlChar *attribute_name, xmlChar *ns_href, int *integer, long int low, long int high) {
1315
	xmlChar *content = NULL;
1316
	gboolean rc = FALSE;
1317
	long int what;
1318

    
1319
	g_assert (integer);
1320
	content = xmlGetNsProp(node, attribute_name, ns_href);
1321
	if (! content)
1322
		goto cleanup;
1323
	if (! lasso_string_to_xsd_integer((char*)content, &what))
1324
		goto cleanup;
1325
	if (what < low || what >= high)
1326
		goto cleanup;
1327
	*integer = what;
1328
	rc = TRUE;
1329
cleanup:
1330
	lasso_release_xml_string(content);
1331
	return rc;
1332
}
1333

    
1334
static inline gboolean
1335
lasso_equal_namespace(xmlNs *t1, xmlNs *t2) {
1336
	return t1 && t2 && (t1 == t2 ||
1337
			lasso_strisequal((char*)t1->href, (char*)t2->href));
1338
}
1339

    
1340
static void
1341
snippet_set_value(LassoNode *node, LassoNodeClass *class, struct XmlSnippet *snippet, xmlChar *content) {
1342
	void *value;
1343
	GType g_type = G_TYPE_FROM_CLASS(class);
1344

    
1345
	/* If not offset, it means it is handled by an adhoc init_from_xml */
1346
	if (! snippet->offset && ! (snippet->type & SNIPPET_PRIVATE)) {
1347
		return;
1348
	}
1349
	value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
1350
	if (snippet->type & SNIPPET_INTEGER) {
1351
		int val = strtol((char*)content, NULL, 10);
1352
		if (((val == INT_MIN || val == INT_MAX) && errno == ERANGE)
1353
				|| errno == EINVAL || val < 0) {
1354
			if (snippet->type & SNIPPET_OPTIONAL_NEG) {
1355
				val = -1;
1356
			} else {
1357
				val = 0;
1358
			}
1359
		}
1360
		(*(int*)value) = val;
1361
	} else if (snippet->type & SNIPPET_BOOLEAN) {
1362
		int val = 0;
1363
		if (strcmp((char*)content, "true") == 0) {
1364
			val = 1;
1365
		} else if (strcmp((char*)content, "1") == 0) {
1366
			val = 1;
1367
		}
1368
		(*(int*)value) = val;
1369
	} else {
1370
		lasso_assign_string((*(char**)value), (char*)content);
1371
		if (lasso_flag_memory_debug == TRUE) {
1372
			fprintf(stderr, "   setting prop %s/%s to value %p: %s\n",
1373
					G_OBJECT_TYPE_NAME(node), snippet->name, *(void**)value, (char*)content);
1374
		}
1375
	}
1376
}
1377

    
1378
gboolean
1379
next_node_snippet(GSList **class_iter_p, struct XmlSnippet **snippet_p)
1380
{
1381
	while (*class_iter_p) {
1382
		if (*snippet_p) {
1383
			if ((*snippet_p)->name) {
1384
				SnippetType type = (*snippet_p)->type;
1385
				/* special case for ArtifactResponse */
1386
				if (type & SNIPPET_ANY && (type & 0xff) == SNIPPET_NODE)
1387
					return TRUE;
1388
				if (! (type & SNIPPET_ANY) && (*snippet_p)->name[0] != '\0') {
1389
					switch (type & 0xff) {
1390
						case SNIPPET_NODE:
1391
						case SNIPPET_NODE_IN_CHILD:
1392
						case SNIPPET_LIST_XMLNODES:
1393
						case SNIPPET_LIST_CONTENT:
1394
						case SNIPPET_LIST_NODES:
1395
						case SNIPPET_EXTENSION:
1396
						case SNIPPET_XMLNODE:
1397
						case SNIPPET_CONTENT:
1398
						case SNIPPET_SIGNATURE:
1399
							return TRUE;
1400
						default:
1401
							break;
1402
					}
1403
				}
1404
				++*snippet_p;
1405
			} else {
1406
				*class_iter_p = g_slist_next(*class_iter_p);
1407
				*snippet_p = NULL;
1408
			}
1409
		} else {
1410
			*snippet_p = ((LassoNodeClass*)(*class_iter_p)->data)
1411
						->node_data->snippets;
1412
		}
1413
	}
1414
	return FALSE;
1415
}
1416

    
1417
static inline gboolean
1418
is_snippet_type(struct XmlSnippet *snippet, SnippetType simple_type) {
1419
	return (snippet->type & 0xff) == simple_type;
1420
}
1421

    
1422
static inline gboolean
1423
is_snippet_mandatory(struct XmlSnippet *snippet)
1424
{
1425
	return snippet->type & SNIPPET_MANDATORY ? TRUE : FALSE;
1426
}
1427

    
1428
static inline gboolean
1429
is_snippet_multiple(struct XmlSnippet *snippet)
1430
{
1431
	switch (snippet->type & 0xff) {
1432
		case SNIPPET_LIST_XMLNODES:
1433
		case SNIPPET_LIST_CONTENT:
1434
		case SNIPPET_LIST_NODES:
1435
		case SNIPPET_EXTENSION:
1436
			return TRUE;
1437
		default:
1438
			return FALSE;
1439
	}
1440
}
1441

    
1442
static inline gboolean
1443
node_match_snippet(xmlNode *parent, xmlNode *node, struct XmlSnippet *snippet)
1444
{
1445
	/* special case of ArtifactResponse */
1446
	if (snippet->type & SNIPPET_ANY) {
1447
		message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs SNIPPET_ANY: SUCCESS", node->name);
1448
		return TRUE;
1449
	} else {
1450
		if (!lasso_strisequal(snippet->name, (char*)node->name)) {
1451
			message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: FAILURE names don't match", node->name, snippet->name);
1452
			return FALSE;
1453
		}
1454

    
1455
		if ((snippet->ns_uri == NULL) && lasso_equal_namespace(parent->ns, node->ns)) {
1456
			message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: SUCCESS namespace prefixes match", node->name, snippet->name);
1457
			return TRUE;
1458
		}
1459

    
1460
		if ((node->ns != NULL) && lasso_strisequal((char*)node->ns->href, snippet->ns_uri)) {
1461
			message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: SUCCESS namespace URIs match", node->name, snippet->name);
1462
			return TRUE;
1463
		}
1464

    
1465
		message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: FAILURE", node->name, snippet->name);
1466
		return FALSE;
1467
	}
1468
}
1469

    
1470
/** FIXME: return a real error code */
1471
static int
1472
lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
1473
{
1474
	struct XmlSnippet *snippet;
1475
	xmlNode *t;
1476
	LassoNodeClass *class;
1477
	void *value;
1478
	SnippetType type;
1479
	struct XmlSnippet *snippet_any = NULL;
1480
	struct XmlSnippet *snippet_any_attribute = NULL;
1481
	GType g_type_collect_namespaces = 0, g_type_any = 0, g_type_any_attribute = 0;
1482
	struct XmlSnippet *snippet_collect_namespaces = NULL;
1483
	struct XmlSnippet *snippet_signature = NULL;
1484
	gboolean keep_xmlnode = FALSE;
1485
	GSList *class_list = NULL;
1486
	GSList *class_iter = NULL;
1487
	xmlAttr *attr = NULL;
1488
	GType g_type = 0;
1489
	LassoNodeClass *node_class;
1490
	gint rc = 0;
1491

    
1492
	message(LOG_LEVEL_XML_DEBUG, "lasso_node_impl_init_from_xml <%s>", xmlnode->name);
1493

    
1494
	if (! xmlnode) {
1495
		rc = 1;
1496
		goto cleanup;
1497
	}
1498

    
1499
	node_class = class = LASSO_NODE_GET_CLASS(node);
1500
	/* No node_data no initialization possible */
1501
	if (! class->node_data) {
1502
		message(G_LOG_LEVEL_WARNING, "Class %s has no node_data so no initialization "
1503
				"is possible", G_OBJECT_CLASS_NAME(class));
1504
		rc = 1;
1505
		goto cleanup;
1506
	}
1507

    
1508
	/* Collect special snippets like SNIPPET_COLLECT_NAMESPACES, SNIPPET_ANY, SNIPPET_ATTRIBUTE
1509
	 * or SNIPPET_SIGNATURE, and initialize class_list in reverse. */
1510
	while (class && LASSO_IS_NODE_CLASS(class)) {
1511
		if (class->node_data) {
1512
			GType g_type = G_TYPE_FROM_CLASS(class);
1513
			keep_xmlnode |= class->node_data->keep_xmlnode;
1514
			if (class->node_data->snippets)
1515
				class_list = g_slist_prepend(class_list, class);
1516
			for (snippet = class->node_data->snippets; snippet && snippet->name; snippet++) {
1517
				type = snippet->type & 0xff;
1518

    
1519
				if (snippet->name && snippet->name[0] == '\0' && type ==
1520
						SNIPPET_COLLECT_NAMESPACES) {
1521
					snippet_collect_namespaces = snippet;
1522
					g_type_collect_namespaces = g_type;
1523
				} else if (type == SNIPPET_SIGNATURE) {
1524
					snippet_signature = snippet;
1525
				} else if (type == SNIPPET_ATTRIBUTE && snippet->type & SNIPPET_ANY) {
1526
					g_type_any_attribute = g_type;
1527
					snippet_any_attribute = snippet;
1528
				} else if (type == SNIPPET_TEXT_CHILD) {
1529
					xmlChar *tmp = xmlNodeGetContent(xmlnode);
1530
					snippet_set_value(node, class, snippet, tmp);
1531
					lasso_release_xml_string(tmp);
1532
				} else if (type != SNIPPET_ATTRIBUTE && type != SNIPPET_NODE && snippet->type & SNIPPET_ANY) {
1533
					if (! snippet_any) {
1534
						g_type_any = g_type;
1535
						snippet_any = snippet;
1536
					} else {
1537
						message(G_LOG_LEVEL_CRITICAL, "Two 'any' node snippet for class %s",
1538
								g_type_name(G_TYPE_FROM_INSTANCE(node)));
1539
					}
1540
				}
1541
			}
1542
		}
1543
		class = g_type_class_peek_parent(class);
1544
	}
1545

    
1546
	/* If any class asked for keeping the xmlNode, keep it around */
1547
	if (keep_xmlnode) {
1548
		lasso_node_set_original_xmlnode(node, xmlnode);
1549
	}
1550

    
1551
	/** Collect attributes */
1552
	for (attr = xmlnode->properties; attr; attr = attr->next) {
1553
		xmlChar *content;
1554
		content = xmlNodeGetContent((xmlNode*)attr);
1555
		int ok = 0;
1556

    
1557
		/* Skip xsi:type if it was used to find the node class */
1558
		if (attr->ns && lasso_strisequal((char*)attr->name, "type") &&
1559
				lasso_strisequal((char*)attr->ns->href, LASSO_XSI_HREF)) {
1560
			char *colon = strchr((char*)content, ':');
1561
			if (colon) {
1562
				xmlNs *ns;
1563
				*colon = '\0';
1564
				ns = xmlSearchNs(NULL, xmlnode, content);
1565
				*colon = ':';
1566
				if (ns && lasso_strisequal((char*)ns->href, (char*)node_class->node_data->ns->href)
1567
						&& lasso_strisequal(&colon[1], node_class->node_data->node_name)) {
1568
					lasso_release_xml_string(content);
1569
					continue;
1570
				}
1571
			}
1572
		}
1573

    
1574
		for (class_iter = class_list; class_iter; class_iter = class_iter->next) {
1575
			class = class_iter->data;
1576
			for (snippet = class->node_data->snippets;
1577
					snippet && snippet->name; snippet++) {
1578
				type = snippet->type & 0xff;
1579
				/* assign attribute content if attribute has the same name as the
1580
				 * snippet and:
1581
				 * - the snippet and the attribute have no namespace
1582
				 * - the snippet has no namespace but the attribute has the same
1583
				 *   namespace as the node
1584
				 * - the snippet and the node have a namespace, which are equal.
1585
				 */
1586
				if (type != SNIPPET_ATTRIBUTE)
1587
					continue;
1588
				if (! lasso_strisequal((char*)attr->name, (char*)snippet->name))
1589
					continue;
1590
				if (attr->ns) {
1591
					gboolean same_namespace, given_namespace;
1592

    
1593
					same_namespace = lasso_equal_namespace(attr->ns,
1594
							xmlnode->ns) && ! snippet->ns_uri;
1595
					given_namespace = snippet->ns_uri &&
1596
						lasso_strisequal((char*)attr->ns->href,
1597
								snippet->ns_uri);
1598
					if (! same_namespace && ! given_namespace)
1599
						break;
1600
				}
1601
				snippet_set_value(node, class, snippet, content);
1602
				ok = 1;
1603
				break;
1604
			}
1605
		}
1606
		if (! ok && attr->ns && snippet_any_attribute) {
1607
			GHashTable **any_attribute;
1608
			gchar *key;
1609

    
1610
			any_attribute = SNIPPET_STRUCT_MEMBER_P(node, g_type_any_attribute,
1611
					snippet_any_attribute);
1612
			if (*any_attribute == NULL) {
1613
				*any_attribute = g_hash_table_new_full(g_str_hash, g_str_equal,
1614
						g_free, g_free);
1615
			}
1616
			if (lasso_equal_namespace(attr->ns, xmlnode->ns)) {
1617
				key = g_strdup((char*)attr->name);
1618
			} else {
1619
				key = g_strdup_printf("{%s}%s", attr->ns->href, attr->name);
1620
			}
1621
			g_hash_table_insert(*any_attribute, key, g_strdup((char*)content));
1622
			lasso_release_xml_string(content);
1623
		} else if (! ok) {
1624
			warning("lasso_node_impl_init_from_xml: Unexpected attribute: {%s}%s = %s",
1625
					attr->ns ? attr->ns->href : NULL, attr->name, content);
1626
		}
1627
		lasso_release_xml_string(content);
1628
	}
1629

    
1630
	/* Collect children nodes in reverse order of class parents (older parent first), skip non
1631
	 * node and ANY snippets) */
1632
	class_iter = class_list;
1633
	snippet = ((LassoNodeClass*)class_iter->data)->node_data->snippets;
1634
	next_node_snippet(&class_iter, &snippet);
1635
	for (t = xmlnode->children; t && class_iter && snippet; t = t->next) {
1636
		/* Only collect text node if:
1637
		 * - there is a LIST_XMLNODES any snippet
1638
		 * - there is a LIST_NODES any snippet with the ALLOW_TEXT modifier
1639
		 */
1640
		if (t->type == XML_TEXT_NODE && snippet_any &&
1641
				(is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)
1642
				 || (is_snippet_type(snippet_any, SNIPPET_LIST_NODES) &&
1643
					 (snippet_any->type & SNIPPET_ALLOW_TEXT)))) {
1644
			GList **location = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any);
1645
			if (is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)) {
1646
				lasso_list_add_xml_node(*location, t);
1647
			} else {
1648
				lasso_list_add_new_gobject(*location,
1649
						lasso_node_new_from_xmlNode_with_type(t,
1650
							"LassoMiscTextNode"));
1651
			}
1652
		} else if (t->type == XML_COMMENT_NODE || t->type == XML_PI_NODE || t->type == XML_TEXT_NODE) {
1653
			/* ignore comments */
1654
			continue;
1655
		} else if (t->type == XML_ELEMENT_NODE) {
1656
			LassoNode *subnode = NULL;
1657
			xmlNode *first_child = NULL;
1658
			GList **list = NULL;
1659
			xmlChar *content = NULL;
1660
			gboolean match = FALSE;
1661
			struct XmlSnippet *matched_snippet = NULL;
1662

    
1663
#define ADVANCE_MATCH \
1664
				if (snippet->type & SNIPPET_JUMP_ON_MATCH) { \
1665
					snippet += (ptrdiff_t)SNIPPET_JUMP_OFFSET(snippet->type); \
1666
				}  else { \
1667
					snippet++; \
1668
				} \
1669
				next_node_snippet(&class_iter, &snippet);
1670
#define ADVANCE_MISS \
1671
				if (snippet->type & SNIPPET_JUMP_ON_MISS) { \
1672
					snippet += (ptrdiff_t)SNIPPET_JUMP_OFFSET(snippet->type); \
1673
				}  else { \
1674
					snippet++; \
1675
				} \
1676
				next_node_snippet(&class_iter, &snippet);
1677
#define ERROR \
1678
				message(G_LOG_LEVEL_CRITICAL, "Element <%s:%s> was not expected at this location inside element <%s>. " \
1679
						"Please ensure the XML correctly follows XML schema", \
1680
						(t->ns == NULL) ? "<noprefix>" : ((t->ns->prefix == NULL)? (char*)t->ns->href : (char*)t->ns->prefix), \
1681
						t->name, \
1682
						xmlnode->name); \
1683
				rc = 1; \
1684
				goto cleanup;
1685
			/* Find a matching snippet */
1686
			while (class_iter && snippet) {
1687
				gboolean mandatory = is_snippet_mandatory(snippet);
1688
				gboolean multiple = is_snippet_multiple(snippet);
1689

    
1690
				if ((match = node_match_snippet(xmlnode, t, snippet))) {
1691
					matched_snippet = snippet;
1692
					class = class_iter->data;
1693
					g_type = G_TYPE_FROM_CLASS(class);
1694
					value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
1695
					list = value;
1696
					if (! multiple || (snippet->type & SNIPPET_JUMP_ON_MATCH)) {
1697
						ADVANCE_MATCH;
1698
					}
1699
					break;
1700
				} else {
1701
					if (mandatory) {
1702
						break;
1703
					} else {
1704
						ADVANCE_MISS;
1705
					}
1706
				}
1707
			}
1708
			if (! match) {
1709
				ERROR;
1710
			}
1711
#undef ADVANCE
1712
#undef ERROR
1713

    
1714
			if (matched_snippet->offset || (matched_snippet->type & SNIPPET_PRIVATE)) {
1715
				switch (matched_snippet->type & 0xff) {
1716
					case SNIPPET_LIST_NODES:
1717
					case SNIPPET_NODE:
1718
						subnode = lasso_node_new_from_xmlNode_with_type(t,
1719
								matched_snippet->class_name);
1720
						if (subnode == NULL) {
1721
							message(G_LOG_LEVEL_CRITICAL, "Failed to create LassoNode from XML node");
1722
						}
1723
						else {
1724
							if (is_snippet_type(matched_snippet, SNIPPET_NODE)) {
1725
								lasso_assign_new_gobject(*(LassoNode**)value, subnode);
1726
							}
1727
							else {
1728
								lasso_list_add_new_gobject(*list, subnode);
1729
							}
1730
						}
1731
						break;
1732
					case SNIPPET_NODE_IN_CHILD:
1733
						first_child = xmlSecGetNextElementNode(t->children);
1734
						if (first_child) {
1735
							subnode = lasso_node_new_from_xmlNode_with_type(first_child,
1736
										matched_snippet->class_name);
1737
							lasso_assign_new_gobject(*(LassoNode**)value, subnode);
1738
						}
1739
						break;
1740
					case SNIPPET_XMLNODE:
1741
						lasso_assign_xml_node(*(xmlNode**)value, t);
1742
						break;
1743
					case SNIPPET_LIST_XMLNODES:
1744
					case SNIPPET_EXTENSION:
1745
						lasso_list_add_xml_node(*list, t);
1746
						break;
1747
					case SNIPPET_CONTENT:
1748
					case SNIPPET_LIST_CONTENT:
1749
						content = xmlNodeGetContent(t);
1750
						if (is_snippet_type(matched_snippet, SNIPPET_CONTENT)) {
1751
							snippet_set_value(node, class, matched_snippet, content);
1752
						} else { /* only list of string-like xsd:type supported */
1753
							lasso_list_add_string(*list, (char*)content);
1754
						}
1755
						lasso_release_xml_string(content);
1756
						break;
1757
					case SNIPPET_SIGNATURE:
1758
						/* We ignore it */
1759
						break;
1760
					default:
1761
						g_assert_not_reached();
1762

    
1763
				}
1764
			}
1765
			/* When creating a new LassoNode and option KEEP_XMLNODE is present,
1766
			 * we attached the xmlNode to the LassoNode */
1767
			if (subnode && (matched_snippet->type & SNIPPET_KEEP_XMLNODE)) {
1768
				lasso_node_set_original_xmlnode(subnode, t);
1769
			}
1770
		} else {
1771
			g_assert_not_reached();
1772
		}
1773
	}
1774
	if (t) { /* t is an ELEMENT that dont match any snippet, when taken in order */
1775
		if (snippet_any && is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)) {
1776
			value = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any);
1777
			GList **list = value;
1778
			for (; t; t = t->next) {
1779
				lasso_list_add_xml_node(*list, t);
1780
			}
1781
		} else if (snippet_any && is_snippet_type(snippet_any, SNIPPET_LIST_NODES)) {
1782
			value = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any);
1783
			GList **list = value;
1784
			for (; t; t = t->next) {
1785
				LassoNode *subnode = NULL;
1786

    
1787
				if (t->type == XML_TEXT_NODE && (snippet_any->type &
1788
							SNIPPET_ALLOW_TEXT)) {
1789
					lasso_list_add_new_gobject(*list,
1790
							lasso_node_new_from_xmlNode_with_type(t,
1791
								"LassoMiscTextNode"));
1792
				} else if (t->type == XML_ELEMENT_NODE) {
1793
					subnode = lasso_node_new_from_xmlNode_with_type(t,
1794
							snippet_any->class_name);
1795
					if (subnode && (snippet_any->type & SNIPPET_KEEP_XMLNODE)) {
1796
						lasso_node_set_original_xmlnode(subnode, t);
1797
					}
1798
					if (! subnode) {
1799
						subnode = (LassoNode*)
1800
							lasso_misc_text_node_new_with_xml_node(t);
1801
					}
1802
					lasso_list_add_new_gobject(*list, subnode);
1803
				}
1804
			}
1805
		} else if (snippet_any) {
1806
			g_assert_not_reached();
1807
		} else {
1808
			for (; t; t = t->next) {
1809
				if (t->type == XML_ELEMENT_NODE) {
1810
					critical("lasso_node_impl_init_from_xml: Cannot match "
1811
							"element {%s}%s with a snippet of "
1812
							"class %s",
1813
							t->ns ?  t->ns->href : NULL, t->name,
1814
							g_type_name(G_TYPE_FROM_INSTANCE(node)));
1815
					rc = 1;
1816
					goto cleanup;
1817
				}
1818
			}
1819
		}
1820
	}
1821

    
1822
	/* Collect namespaces on the current node */
1823
	if (snippet_collect_namespaces) {
1824
		void *value = SNIPPET_STRUCT_MEMBER_P(node, g_type_collect_namespaces,
1825
				snippet_collect_namespaces);
1826
		_lasso_node_collect_namespaces(value, xmlnode);
1827
	}
1828

    
1829
	/* Collect signature parameters */
1830
	{
1831
			LassoSignatureMethod method = 0;
1832
			xmlChar *private_key = NULL;
1833
			xmlChar *private_key_password = NULL;
1834
			xmlChar *certificate = NULL;
1835
			LassoSignatureContext signature_context = LASSO_SIGNATURE_CONTEXT_NONE;
1836

    
1837
		while (snippet_signature) {
1838
			int what;
1839
			if (! lasso_get_integer_attribute(xmlnode, LASSO_SIGNATURE_METHOD_ATTRIBUTE,
1840
						BAD_CAST LASSO_LIB_HREF, &what,
1841
						LASSO_SIGNATURE_METHOD_RSA_SHA1,
1842
						LASSO_SIGNATURE_METHOD_LAST))
1843
				break;
1844
			method = what;
1845
			if (! lasso_get_integer_attribute(xmlnode, LASSO_SIGNATURE_METHOD_ATTRIBUTE,
1846
					BAD_CAST LASSO_LIB_HREF, &what, LASSO_SIGNATURE_TYPE_NONE+1,
1847
					LASSO_SIGNATURE_TYPE_LAST))
1848
				break;
1849
			private_key_password = xmlGetNsProp(xmlnode, LASSO_PRIVATE_KEY_PASSWORD_ATTRIBUTE,
1850
				BAD_CAST LASSO_LIB_HREF);
1851
			if (! private_key)
1852
				break;
1853
			private_key = xmlGetNsProp(xmlnode, LASSO_PRIVATE_KEY_ATTRIBUTE, BAD_CAST
1854
				LASSO_LIB_HREF);
1855
			certificate = xmlGetNsProp(xmlnode, LASSO_CERTIFICATE_ATTRIBUTE, BAD_CAST
1856
				LASSO_LIB_HREF);
1857

    
1858
			signature_context.signature_method = method;
1859
			signature_context.signature_key = lasso_xmlsec_load_private_key((char*) private_key,
1860
					(char*) private_key_password, method, (char*) certificate);
1861
			lasso_node_set_signature(node, signature_context);
1862
			break;
1863
		}
1864
		lasso_release_xml_string(private_key);
1865
		lasso_release_xml_string(private_key_password);
1866
		lasso_release_xml_string(certificate);
1867
	}
1868
cleanup:
1869
	lasso_release_slist(class_list);
1870
	message(LOG_LEVEL_XML_DEBUG, "lasso_node_impl_init_from_xml </%s> rc=%d", xmlnode->name, rc);
1871
	return rc;
1872
}
1873
#undef trace_snippet
1874

    
1875
/**
1876
 * lasso_node_remove_signature:
1877
 * @node: a #LassoNode object
1878
 *
1879
 * Remove any signature setup on this node.
1880
 */
1881
void
1882
lasso_node_remove_signature(LassoNode *node) {
1883
       LassoNodeClass *klass;
1884

    
1885
       if (! LASSO_IS_NODE(node))
1886
               return;
1887
       klass = LASSO_NODE_GET_CLASS(node);
1888
       /* follow the class parenting chain */
1889
       while (klass && LASSO_IS_NODE_CLASS(klass)) {
1890
               if (klass && klass->node_data && klass->node_data->sign_type_offset != 0) {
1891
                       G_STRUCT_MEMBER(LassoSignatureType, node, klass->node_data->sign_type_offset) =
1892
                               LASSO_SIGNATURE_TYPE_NONE;
1893
               }
1894
               klass = g_type_class_peek_parent(klass);
1895
       }
1896
       lasso_node_set_signature(node, LASSO_SIGNATURE_CONTEXT_NONE);
1897
}
1898

    
1899
/*****************************************************************************/
1900
/* private methods                                                           */
1901
/*****************************************************************************/
1902

    
1903
static void
1904
_xmlnode_add_custom_namespace(const char *prefix, const char *href, xmlNode *xmlnode)
1905
{
1906
	xmlNs *existing = NULL;
1907

    
1908
	existing = xmlSearchNs(NULL, xmlnode, BAD_CAST prefix);
1909
	if (existing) {
1910
		if (lasso_strisnotequal((char *)existing->href,href)) {
1911
			message(G_LOG_LEVEL_CRITICAL, "Cannot add namespace %s='%s' to node %s, "
1912
					"namespace already exists with another href", prefix, href,
1913
					(char*)xmlnode->name);
1914
		}
1915
		return;
1916
	}
1917
	xmlNewNs(xmlnode, BAD_CAST href, BAD_CAST prefix);
1918
}
1919

    
1920
static char*
1921
lasso_node_impl_build_query(LassoNode *node)
1922
{
1923
	return lasso_node_build_query_from_snippets(node);
1924
}
1925

    
1926
static xmlNode*
1927
lasso_node_impl_get_xmlNode(LassoNode *node, gboolean lasso_dump)
1928
{
1929
	LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
1930
	LassoNodeClass *version_class = NULL;
1931
	xmlNode *xmlnode;
1932
	xmlNs *ns = NULL;
1933
	GSList *list_classes = NULL, *iter_classes = NULL;
1934
	LassoNode *value_node;
1935
	struct XmlSnippet *version_snippet;
1936
	struct _CustomElement *custom_element;
1937
	LassoNodeClass *xsi_sub_type_data_class = NULL;
1938
	LassoNodeClass *node_name_class = class;
1939

    
1940
	while (node_name_class->node_data->xsi_sub_type) {
1941
		node_name_class= g_type_class_peek_parent(node_name_class);
1942
	}
1943
	if (node_name_class != class) {
1944
		xsi_sub_type_data_class = class;
1945
	}
1946
	g_assert(node_name_class && node_name_class->node_data &&
1947
			node_name_class->node_data->node_name);
1948

    
1949
	/* Create node in its namespace */
1950
	xmlnode = xmlNewNode(NULL, (xmlChar*)node_name_class->node_data->node_name);
1951
	if (node_name_class->node_data->ns) {
1952
		ns = get_or_define_ns(xmlnode, node_name_class->node_data->ns->href,
1953
				node_name_class->node_data->ns->prefix);
1954
		xmlSetNs(xmlnode, ns);
1955
	}
1956
	/* If subtype, set an xsi:type attribute */
1957
	if (xsi_sub_type_data_class) {
1958
		set_xsi_type(xmlnode,
1959
				xsi_sub_type_data_class->node_data->ns->prefix,
1960
				xsi_sub_type_data_class->node_data->ns->href,
1961
				BAD_CAST xsi_sub_type_data_class->node_data->node_name);
1962
	}
1963
	custom_element = _lasso_node_get_custom_element(node);
1964

    
1965
	/* collect all classes in reverse order */
1966
	while (class && LASSO_IS_NODE_CLASS(class)) {
1967
		if (class->node_data && class->node_data->snippets)
1968
			list_classes = g_slist_prepend(list_classes, class);
1969
		class = g_type_class_peek_parent(class);
1970
	}
1971

    
1972
	/* set a custom namespace if one is found */
1973
	if (custom_element != NULL) {
1974
		if (custom_element->href) {
1975
			xmlChar *prefix = BAD_CAST (custom_element->prefix);
1976
			xmlNs *ns = NULL, *oldns = NULL;
1977

    
1978
			oldns = xmlSearchNs(NULL, xmlnode, prefix);
1979
			if (prefix && oldns) {
1980
				prefix = NULL;
1981
			}
1982
			// remove existing default namespace
1983
			if (prefix == NULL) {
1984
				xmlNs *cur = xmlnode->nsDef, *last = NULL;
1985
				while (cur) {
1986
					if (cur->prefix == NULL) {
1987
						if (last) {
1988
							last->next = cur->next;
1989
						} else {
1990
							xmlnode->nsDef = cur->next;
1991
						}
1992
						xmlFreeNs(cur);
1993
					}
1994
					last = cur;
1995
					cur = cur->next;
1996
				}
1997
			}
1998
			ns = xmlNewNs(xmlnode, (xmlChar*)custom_element->href,
1999
					(xmlChar*)custom_element->prefix);
2000
			/* skip the base class namespace, it is replaced by the custom one */
2001
			xmlSetNs(xmlnode, ns);
2002
		}
2003
		if (custom_element->nodename) {
2004
			xmlNodeSetName(xmlnode, BAD_CAST (custom_element->nodename));
2005
		}
2006
		g_hash_table_foreach(custom_element->namespaces,
2007
				(GHFunc)_xmlnode_add_custom_namespace, xmlnode);
2008
	}
2009

    
2010

    
2011
	for (iter_classes = list_classes; iter_classes; iter_classes = g_slist_next(iter_classes)) {
2012
		class = iter_classes->data;
2013
		lasso_node_build_xmlNode_from_snippets(node,
2014
				(LassoNodeClass*)class, xmlnode,
2015
				class->node_data->snippets,
2016
				lasso_dump);
2017
	}
2018

    
2019
	xmlCleanNs(xmlnode);
2020

    
2021
	/* backward compatibility with Liberty ID-FF 1.1; */
2022
	if (find_path(node, "MajorVersion", &value_node, &version_class, &version_snippet) == TRUE) {
2023
		int *value;
2024
		int major_version, minor_version;
2025

    
2026
		value = SNIPPET_STRUCT_MEMBER_P(value_node, G_TYPE_FROM_CLASS(version_class),
2027
				version_snippet);
2028
		major_version = *value;
2029

    
2030
		if (find_path(node, "MinorVersion", &value_node, &version_class, &version_snippet) == TRUE) {
2031
			value = SNIPPET_STRUCT_MEMBER_P(value_node, G_TYPE_FROM_CLASS(version_class),
2032
					version_snippet);
2033
			minor_version = *value;
2034
		} else {
2035
			minor_version = 0;
2036
		}
2037

    
2038
		if (strcmp((char*)xmlnode->ns->href, LASSO_LIB_HREF) == 0) {
2039
			if (major_version == 1 && minor_version == 0) {
2040
				xmlFree((xmlChar*)xmlnode->ns->href); /* warning: discard const */
2041
				xmlnode->ns->href = xmlStrdup((xmlChar*)
2042
						"http://projectliberty.org/schemas/core/2002/12");
2043
			}
2044
		}
2045
	}
2046

    
2047
	g_slist_free(list_classes);
2048
	return xmlnode;
2049
}
2050

    
2051
/*****************************************************************************/
2052
/* overridden parent class methods                                           */
2053
/*****************************************************************************/
2054

    
2055
static GObjectClass *parent_class = NULL;
2056

    
2057
static void
2058
lasso_node_dispose(GObject *object)
2059
{
2060
	LassoNodeClass *class;
2061
	struct XmlSnippet *snippet;
2062
	SnippetType type;
2063

    
2064
	if (lasso_flag_memory_debug == TRUE) {
2065
		fprintf(stderr, "dispose of %s (at %p)\n", G_OBJECT_TYPE_NAME(object), object);
2066
	}
2067

    
2068
	class = LASSO_NODE_GET_CLASS(object);
2069

    
2070
	while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
2071
		for (snippet = class->node_data->snippets; snippet && snippet->name; snippet++) {
2072
			void **value = SNIPPET_STRUCT_MEMBER_P(object, G_TYPE_FROM_CLASS(class), snippet);
2073
			type = snippet->type & 0xff;
2074

    
2075
			if (! snippet->offset && ! (snippet->type & SNIPPET_PRIVATE))
2076
				continue;
2077
			if (snippet->type & SNIPPET_BOOLEAN)
2078
				continue;
2079
			if (snippet->type & SNIPPET_INTEGER)
2080
				continue;
2081

    
2082
			if (*value == NULL)
2083
				continue;
2084

    
2085
			if (lasso_flag_memory_debug == TRUE) {
2086
				fprintf(stderr, "  freeing %s/%s (at %p)\n",
2087
						G_OBJECT_TYPE_NAME(object), snippet->name, *value);
2088
			}
2089
			switch (type) {
2090
				case SNIPPET_NODE:
2091
				case SNIPPET_NODE_IN_CHILD:
2092
					lasso_release_gobject(*value);
2093
					break;
2094
				case SNIPPET_XMLNODE:
2095
					xmlFreeNode(*value);
2096
					break;
2097
				case SNIPPET_LIST_NODES:
2098
					lasso_release_list_of_gobjects((*(GList**)value));
2099
					break;
2100
				case SNIPPET_EXTENSION:
2101
				case SNIPPET_LIST_XMLNODES:
2102
					lasso_release_list_of_xml_node(*(GList**)value);
2103
					break;
2104
				case SNIPPET_LIST_CONTENT:
2105
					lasso_release_list_of_strings(*(GList**)value);
2106
					break;
2107
				case SNIPPET_CONTENT:
2108
				case SNIPPET_TEXT_CHILD:
2109
				case SNIPPET_ATTRIBUTE: {
2110
								if (snippet->type & SNIPPET_ANY) {
2111
									if (*value) {
2112
										lasso_release_ghashtable(*value);
2113
									}
2114
								} else {
2115
									lasso_release_string(*(char**)value);
2116
								}
2117
							} break;
2118
				case SNIPPET_SIGNATURE:
2119
							break; /* no real element here */
2120
				case SNIPPET_COLLECT_NAMESPACES:
2121
					if (*value) {
2122
						lasso_release_ghashtable(*value);
2123
					}
2124
					break;
2125
				default:
2126
							fprintf(stderr, "%d\n", type);
2127
							g_assert_not_reached();
2128
			}
2129

    
2130
			if (type != SNIPPET_SIGNATURE) {
2131
				/* Signature snippet is not something to free,
2132
				 * so don't set the value to NULL */
2133
				*value = NULL;
2134
			}
2135
		}
2136
		class = g_type_class_peek_parent(class);
2137
	}
2138

    
2139
	parent_class->dispose(object);
2140
}
2141

    
2142
/*****************************************************************************/
2143
/* instance and class init functions                                         */
2144
/*****************************************************************************/
2145

    
2146
static gboolean
2147
init_from_query(LassoNode *node, char **query_fields)
2148
{
2149
	return lasso_node_init_from_query_fields(node, query_fields);
2150
}
2151

    
2152
static void
2153
class_init(LassoNodeClass *class)
2154
{
2155
	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
2156

    
2157
	parent_class = g_type_class_peek_parent(class);
2158
	/* virtual public methods */
2159
	class->destroy = lasso_node_impl_destroy;
2160
	class->init_from_query = init_from_query;
2161
	class->init_from_xml = lasso_node_impl_init_from_xml;
2162

    
2163
	/* virtual private methods */
2164
	class->build_query = lasso_node_impl_build_query;
2165
	class->get_xmlNode = lasso_node_impl_get_xmlNode;
2166

    
2167
	/* override */
2168
	gobject_class->dispose = lasso_node_dispose;
2169

    
2170
	original_xmlnode_quark = g_quark_from_static_string("lasso_original_xmlnode");
2171
	custom_element_quark = g_quark_from_static_string("lasso_custom_element");
2172
	class->node_data = NULL;
2173
}
2174

    
2175
static void
2176
base_class_finalize(LassoNodeClass *class)
2177
{
2178
	if (class->node_data) {
2179
		LassoNodeClassData *data = class->node_data;
2180

    
2181
		if (data->ns) {
2182
			xmlFreeNs(data->ns);
2183
		}
2184
		if (data->node_name) {
2185
			lasso_release(data->node_name);
2186
		}
2187
		lasso_release(class->node_data);
2188
		class->node_data = NULL;
2189
	}
2190
}
2191

    
2192
GType
2193
lasso_node_get_type()
2194
{
2195
	static GType this_type = 0;
2196

    
2197
	if (!this_type) {
2198
		static const GTypeInfo this_info = {
2199
			sizeof (LassoNodeClass),
2200
			NULL,
2201
			(GBaseFinalizeFunc) base_class_finalize,
2202
			(GClassInitFunc) class_init,
2203
			NULL,
2204
			NULL,
2205
			sizeof(LassoNode),
2206
			0,
2207
			NULL,
2208
			NULL,
2209
		};
2210

    
2211
		this_type = g_type_register_static(G_TYPE_OBJECT , "LassoNode", &this_info, 0);
2212
	}
2213
	return this_type;
2214
}
2215

    
2216
/**
2217
 * lasso_node_new:
2218
 *
2219
 * Creates a new #LassoNode.
2220
 *
2221
 * Return value: a newly created #LassoNode object
2222
 **/
2223
LassoNode*
2224
lasso_node_new()
2225
{
2226
	return g_object_new(LASSO_TYPE_NODE, NULL);
2227
}
2228

    
2229
/**
2230
 * lasso_node_new_from_dump:
2231
 * @dump: XML object dump
2232
 *
2233
 * Restores the @dump to a new #LassoNode subclass.
2234
 *
2235
 * Return value: a newly created object; or NULL if an error occured.
2236
 **/
2237
LassoNode*
2238
lasso_node_new_from_dump(const char *dump)
2239
{
2240
	LassoNode *node;
2241
	xmlDoc *doc;
2242

    
2243
	if (dump == NULL)
2244
		return NULL;
2245

    
2246
	doc = lasso_xml_parse_memory(dump, strlen(dump));
2247
	if (doc == NULL)
2248
		return NULL;
2249

    
2250
	node = lasso_node_new_from_xmlNode(xmlDocGetRootElement(doc));
2251

    
2252
	lasso_release_doc(doc);
2253
	return node;
2254
}
2255

    
2256

    
2257
/**
2258
 * lasso_node_new_from_soap:
2259
 * @soap: the SOAP message
2260
 *
2261
 * Parses SOAP message and creates a new Lasso object with the right class.
2262
 *
2263
 * Return value: node if success; NULL otherwise
2264
 **/
2265
LassoNode*
2266
lasso_node_new_from_soap(const char *soap)
2267
{
2268
	xmlDoc *doc;
2269
	xmlNode *xmlnode;
2270
	LassoNode *node = NULL;
2271

    
2272
	doc = lasso_xml_parse_memory(soap, strlen(soap));
2273
	if (doc == NULL) {
2274
		return NULL;
2275
	}
2276
	xmlnode = lasso_xml_get_soap_content(xmlDocGetRootElement(doc));
2277
	if (xmlnode == NULL) {
2278
		return NULL;
2279
	}
2280
	node = lasso_node_new_from_xmlNode(xmlnode);
2281

    
2282
	lasso_release_doc(doc);
2283

    
2284
	return node;
2285
}
2286

    
2287
/* How finding a typename from an xmlNode works ?
2288
 *
2289
 * There is three way to get to a typename:
2290
 * 1. by an xsi:type QName attribute, that we resolve
2291
 * 2. by constructing a QName from the namespace of the xsi:type and the name of the node
2292
 * 3. by resolving the QName of the node
2293
 *
2294
 * To resolve a typename you must map the QName using the default registry object, or use
2295
 * prefix_from_href_and_nodename() to mat the QName to a prefix used to build the typename with this
2296
 * template: typename = "Lasso" + prefix + name_part(QName).
2297
 *
2298
 * The resolving algorithm is in the function _type_name_from_href_and_nodename().
2299
 *
2300
 * The prefix extraction in prefix_from_href_and_nodename().
2301
 *
2302
 */
2303
static const char *
2304
prefix_from_href_and_nodename(const xmlChar *href, G_GNUC_UNUSED const xmlChar *nodename) {
2305
	char *prefix = NULL;
2306
#ifdef LASSO_WSF_ENABLED
2307
	char *tmp = NULL;
2308
#endif
2309

    
2310
	if (strcmp((char*)href, LASSO_LASSO_HREF) == 0)
2311
		prefix = "";
2312
	else if (strcmp((char*)href, LASSO_SAML_ASSERTION_HREF) == 0)
2313
		prefix = "Saml";
2314
	else if (strcmp((char*)href, LASSO_SAML_PROTOCOL_HREF) == 0)
2315
		prefix = "Samlp";
2316
	else if (strcmp((char*)href, LASSO_LIB_HREF) == 0)
2317
		prefix = "Lib";
2318
	else if (strcmp((char*)href, LASSO_SAML2_ASSERTION_HREF) == 0)
2319
		prefix = "Saml2";
2320
	else if (strcmp((char*)href, LASSO_SAML2_PROTOCOL_HREF) == 0)
2321
		prefix = "Samlp2";
2322
	else if (strcmp((char*)href, LASSO_ECP_HREF) == 0)
2323
		prefix = "Ecp";
2324
	else if (strcmp((char*)href, LASSO_PAOS_HREF) == 0)
2325
		prefix = "Paos";
2326
	else if (strcmp((char*)href, LASSO_SOAP_ENV_HREF) == 0)
2327
		prefix = "Soap";
2328
	else if (strcmp((char*)href, LASSO_DS_HREF) == 0)
2329
		prefix = "Ds";
2330
#ifdef LASSO_WSF_ENABLED
2331
	else if (strcmp((char*)href, LASSO_SOAP_BINDING_HREF) == 0)
2332
		prefix = "SoapBinding";
2333
	else if (strcmp((char*)href, LASSO_SOAP_BINDING_EXT_HREF) == 0)
2334
		prefix = "SoapBindingExt";
2335
	else if (strcmp((char*)href, LASSO_DISCO_HREF) == 0)
2336
		prefix = "Disco";
2337
	else if (strcmp((char*)href, LASSO_IS_HREF) == 0)
2338
		prefix = "Is";
2339
	else if (strcmp((char*)href, LASSO_SA_HREF) == 0)
2340
		prefix = "Sa";
2341
	else if (strcmp((char*)href, LASSO_WSSE_HREF) == 0)
2342
		prefix = "WsSec1";
2343
	else if (strcmp((char*)href, LASSO_WSSE1_HREF) == 0)
2344
		prefix = "WsSec1";
2345
	else if (strcmp((char*)href, LASSO_IDWSF2_DISCOVERY_HREF) == 0)
2346
		prefix = "IdWsf2Disco";
2347
	else if (strcmp((char*)href, LASSO_IDWSF2_SBF_HREF) == 0)
2348
		prefix = "IdWsf2Sbf";
2349
	else if (strcmp((char*)href, LASSO_IDWSF2_SB2_HREF) == 0)
2350
		prefix = "IdWsf2Sb2";
2351
	else if (strcmp((char*)href, LASSO_IDWSF2_UTIL_HREF) == 0)
2352
		prefix = "IdWsf2Util";
2353
	else if (strcmp((char*)href, LASSO_IDWSF2_SEC_HREF) == 0)
2354
		prefix = "IdWsf2Sec";
2355
	else if (strcmp((char*)href, LASSO_IDWSF2_IMS_HREF) == 0)
2356
		prefix = "IdWsf2Ims";
2357
	else if (strcmp((char*)href, LASSO_IDWSF2_IS_HREF) == 0)
2358
		prefix = "IdWsf2Is";
2359
	else if (strcmp((char*)href, LASSO_IDWSF2_PS_HREF) == 0)
2360
		prefix = "IdWsf2Ps";
2361
	else if (strcmp((char*)href, LASSO_IDWSF2_SUBS_HREF) == 0)
2362
		prefix = "IdWsf2Subs";
2363
	else if (strcmp((char*)href, LASSO_IDWSF2_SUBSREF_HREF) == 0)
2364
		prefix = "IdWsf2SubsRef";
2365
	else if (strcmp((char*)href, LASSO_WSA_HREF) == 0)
2366
		prefix = "WsAddr";
2367
#if 0 /* Desactivate DGME lib special casing */
2368
	else if (strcmp((char*)href, "urn:dgme:msp:ed:2007-01") == 0)
2369
		/* FIXME: new namespaces should be possible to add from another library than lasso */
2370
		prefix = "DgmeMspEd";
2371
#endif
2372
	else if ((tmp = lasso_get_prefix_for_idwsf2_dst_service_href((char*)href))
2373
			!= NULL) {
2374
		/* ID-WSF 2 Profile */
2375
		prefix = "IdWsf2DstRef";
2376
		lasso_release_string(tmp);
2377
	} else if ((tmp = lasso_get_prefix_for_dst_service_href((char*)href))
2378
			!= NULL) {
2379
		/* ID-WSF 1 Profile */
2380
		prefix = "Dst";
2381
		lasso_release_string(tmp);
2382
	}
2383

    
2384
	if (prefix != NULL && strcmp(prefix, "Dst") == 0 && strcmp((char*)nodename, "Status") == 0)
2385
		prefix = "Utility";
2386
	else if (prefix != NULL && strcmp(prefix, "Disco") == 0 && strcmp((char*)nodename, "Status") == 0)
2387
		prefix = "Utility";
2388
	else if (prefix != NULL && strcmp(prefix, "Sa") == 0 && strcmp((char*)nodename, "Status") == 0)
2389
		prefix = "Utility";
2390
#endif
2391

    
2392
	return prefix;
2393
}
2394

    
2395
/*
2396
 * _type_name_from_href_and_nodename:
2397
 * @href: the href part of a QName
2398
 * @nodename: the name part of a QName
2399
 *
2400
 * Return value: a typename string if one if found that exists, NULL otherwise.
2401
 */
2402
static char*
2403
_type_name_from_href_and_nodename(char *href, char *nodename) {
2404
	const char *prefix = prefix_from_href_and_nodename(BAD_CAST (href), BAD_CAST (nodename));
2405
	char *typename = NULL;
2406

    
2407
	if (!href || !nodename)
2408
		return NULL;
2409

    
2410
	/* FIXME: hardcoded mappings */
2411
	if (strcmp(nodename, "SvcMD") == 0) {
2412
		typename = g_strdup("LassoIdWsf2DiscoSvcMetadata");
2413
	} else if (prefix != NULL && strcmp(prefix, "IdWsf2DstRef") == 0 && strcmp(nodename, "Status") == 0) {
2414
		typename = g_strdup("LassoIdWsf2UtilStatus");
2415
	} else if (prefix != NULL && strcmp(prefix, "WsSec1") == 0 && strcmp(nodename, "Security") == 0) {
2416
		typename = g_strdup("LassoWsSec1SecurityHeader");
2417
	} else if (prefix != NULL && strcmp(prefix, "Soap") == 0 && strcmp(nodename, "detail") == 0) {
2418
		typename = g_strdup("LassoSoapDetail");
2419
	} else {
2420
		/* first try with registered mappings */
2421
		const char *ctypename = lasso_registry_default_get_mapping(href, nodename, LASSO_LASSO_HREF);
2422
		if (ctypename) {
2423
			typename = g_strdup(ctypename);
2424
		}
2425
		/* finally try the default behaviour */
2426
		if (prefix != NULL && typename == NULL) {
2427
			typename = g_strdup_printf("Lasso%s%s", prefix, nodename);
2428
		}
2429
	}
2430

    
2431
	/* Does it really exist ? */
2432
	if (typename && g_type_from_name (typename) == 0) {
2433
		lasso_release_string(typename);
2434
	}
2435

    
2436
	return typename;
2437
}
2438

    
2439
/**
2440
 * _lasso_node_new_from_xmlNode:
2441
 * @node: an xmlNode
2442
 *
2443
 * Builds a new #LassoNode from an xmlNode.
2444
 *
2445
 * Return value: a new node
2446
 **/
2447
static LassoNode*
2448
_lasso_node_new_from_xmlNode(xmlNode *xmlnode)
2449
{
2450
	char *typename = NULL;
2451
	xmlChar *xsitype = NULL;
2452
	LassoNode *node = NULL;
2453
	gboolean fromXsi = FALSE;
2454

    
2455
	xsitype = xmlGetNsProp(xmlnode, (xmlChar*)"type", (xmlChar*)LASSO_XSI_HREF);
2456
	if (xsitype) {
2457
		xmlChar *xmlPrefix, *separator;
2458
		xmlNsPtr xsiNs = NULL;
2459
		char *xsiNodeName = NULL;
2460

    
2461
		/** Honor xsi:type  */
2462
		xmlPrefix = (xmlChar*)xsitype;
2463
		separator = (xmlChar*)strchr((char*)xsitype, ':');
2464
		if (separator != NULL) {
2465
			xmlPrefix = (xmlChar*)g_strndup((char*)xmlPrefix, (size_t)(separator - xmlPrefix));
2466
			xsiNs = xmlSearchNs(NULL, xmlnode, xmlPrefix);
2467
			if (xsiNs != NULL) {
2468
				xsiNodeName = g_strdup((char*)(separator+1));
2469
				if (strcmp((char*)xsiNs->href, LASSO_LASSO_HREF) == 0) {
2470
					typename = g_strdup(xsiNodeName);
2471
				}
2472
			}
2473
			lasso_release(xmlPrefix);
2474
		}
2475
		if (! typename && xsiNs && xsiNodeName) {
2476
			typename = _type_name_from_href_and_nodename ((char*)xsiNs->href, xsiNodeName);
2477
		}
2478
		if (! typename && xsiNs) {
2479
			typename = _type_name_from_href_and_nodename ((char*)xsiNs->href, (char*)xmlnode->name);
2480
		}
2481
		lasso_release_xml_string(xsitype);
2482
		if (xsiNodeName)
2483
			lasso_release_string(xsiNodeName);
2484
		if (typename)
2485
			fromXsi = TRUE;
2486
	}
2487

    
2488
	if (typename == NULL && xmlnode->ns && xmlnode->ns->href) {
2489
		typename = _type_name_from_href_and_nodename ((char*)xmlnode->ns->href, (char*)xmlnode->name);
2490
	}
2491

    
2492
	if (typename) {
2493
		node = lasso_node_new_from_xmlNode_with_type(xmlnode, typename);
2494
	}
2495
	if (! node) {
2496
		goto cleanup;
2497
	}
2498
	if (! fromXsi) {
2499
		/* if the typename was not obtained via xsi:type but through mapping of the element
2500
		 * name then keep the element name */
2501
		if (LASSO_NODE_GET_CLASS(node)->node_data &&
2502
				LASSO_NODE_GET_CLASS(node)->node_data->node_name &&
2503
				lasso_strisnotequal((char*)xmlnode->name,
2504
					LASSO_NODE_GET_CLASS(node)->node_data->node_name))
2505
		{
2506
			lasso_node_set_custom_nodename(node, (char*)xmlnode->name);
2507
		}
2508

    
2509
		if (xmlnode->ns && (LASSO_NODE_GET_CLASS(node)->node_data == NULL ||
2510
					LASSO_NODE_GET_CLASS(node)->node_data->ns == NULL ||
2511
					lasso_xmlstrisnotequal(xmlnode->ns->href,
2512
						LASSO_NODE_GET_CLASS(node)->node_data->ns->href)))
2513
		{
2514
			lasso_node_set_custom_namespace(node, (char*)xmlnode->ns->prefix,
2515
					(char*)xmlnode->ns->href);
2516
		}
2517

    
2518

    
2519
	}
2520
cleanup:
2521
	lasso_release(typename);
2522

    
2523
	return node;
2524
}
2525

    
2526
/**
2527
 * lasso_node_new_from_xmlNode:
2528
 * @node: an xmlNode
2529
 *
2530
 * Builds a new #LassoNode from an xmlNode.
2531
 *
2532
 * Return value: a new node
2533
 **/
2534
LassoNode*
2535
lasso_node_new_from_xmlNode(xmlNode *xmlnode)
2536
{
2537
	if (xmlnode == NULL || xmlnode->ns == NULL) {
2538
		message(G_LOG_LEVEL_CRITICAL, "Unable to build a LassoNode from a xmlNode");
2539
		return NULL;
2540
	}
2541
	return _lasso_node_new_from_xmlNode(xmlnode);
2542
}
2543

    
2544
static LassoNode*
2545
lasso_node_new_from_xmlNode_with_type(xmlNode *xmlnode, char *typename)
2546
{
2547
	GType gtype;
2548
	LassoNode *node;
2549
	int rc = 0;
2550

    
2551
	message(LOG_LEVEL_XML_DEBUG, "Processing node '%s' with type '%s'", xmlnode->name, typename); 
2552

    
2553
	if (typename == NULL) {
2554
		return _lasso_node_new_from_xmlNode(xmlnode); /* will auto-detect */
2555
	}
2556

    
2557
	gtype = g_type_from_name(typename);
2558
	if (gtype == 0) {
2559
		message(G_LOG_LEVEL_CRITICAL, "Unable to get g_type from name '%s'", typename);
2560
		return NULL;
2561
	}
2562

    
2563

    
2564
	node = g_object_new(gtype, NULL);
2565
	if (lasso_flag_memory_debug == TRUE) {
2566
		fprintf(stderr, "allocation of %s (for xmlNode %p) : %p\n", g_type_name(gtype), xmlnode, node);
2567
	}
2568
	rc = lasso_node_init_from_xml(node, xmlnode);
2569
	if (rc) {
2570
		message(G_LOG_LEVEL_CRITICAL, "Lasso node initialization failed for node '%s', type '%s': error %d", xmlnode->name, typename, rc);
2571
		lasso_node_destroy(node);
2572
		return NULL;
2573
	}
2574

    
2575
	return node;
2576
}
2577

    
2578
static gboolean
2579
is_base64(const char *message)
2580
{
2581
	const char *c;
2582

    
2583
	c = message;
2584
	while (*c != 0 && (isalnum((int)*c) || *c == '+' || *c == '/' || *c == '\n' || *c == '\r')) c++;
2585
	while (*c == '=' || *c == '\n' || *c == '\r') c++; /* trailing = */
2586

    
2587
	if (*c == 0)
2588
		return TRUE;
2589

    
2590
	return FALSE;
2591
}
2592

    
2593

    
2594
/**
2595
 * lasso_node_init_from_message_with_format:
2596
 * @node: a #LassoNode (or derived class)
2597
 * @message: a Liberty message
2598
 * @constraint: LASSO_MESSAGE_FORMAT_UNKNOWN or the format the message must be in
2599
 * @doc_out: a pointer to store the resulting #xmlDoc structure
2600
 * @node_out: a pointer to store the resulting content #xmlNode
2601
 *
2602
 * Parses @message and initialiazes @node fields with data from it.  Message type may be base64,
2603
 * SOAP, XML or query string, correct type is found automatically if contraint is
2604
 * LASSO_MESSAGE_FORMAT_UNKNOWN or is limited to the value given.
2605
 * If the format is one of LASSO_MESSAGE_FORMAT_XML or LASSO_MESSAGE_FORMAT_XML or
2606
 * LASSO_MESSAGE_FORMAT_BASE64 the resulting #xmlDoc and #xmlNode of the message can be retrieved.
2607
 *
2608
 * Return value: a #LassoMessageFormat value.
2609
 **/
2610
LassoMessageFormat
2611
lasso_node_init_from_message_with_format(LassoNode *node, const char *message, LassoMessageFormat constraint, xmlDoc **doc_out, xmlNode **root_out)
2612
{
2613
	char *msg = NULL;
2614
	gboolean b64 = FALSE;
2615
	LassoMessageFormat rc = LASSO_MESSAGE_FORMAT_ERROR;
2616
	xmlDoc *doc = NULL;
2617
	xmlNode *root = NULL;
2618
	gboolean any = constraint == LASSO_MESSAGE_FORMAT_UNKNOWN;
2619

    
2620
	msg = (char*)message;
2621

    
2622
	/* BASE64 case */
2623
	if (any || constraint == LASSO_MESSAGE_FORMAT_BASE64) {
2624
		if (message[0] != 0 && is_base64(message)) {
2625
			int rc = 0;
2626

    
2627
			msg = g_malloc(strlen(message));
2628
			rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)msg, strlen(message));
2629
			if (rc >= 0) {
2630
				b64 = TRUE;
2631
			} else {
2632
				lasso_release(msg);
2633
				msg = (char*)message;
2634
			}
2635
		}
2636
	}
2637

    
2638
	/* XML case */
2639
	if (any || constraint == LASSO_MESSAGE_FORMAT_XML ||
2640
		constraint == LASSO_MESSAGE_FORMAT_BASE64 ||
2641
		constraint == LASSO_MESSAGE_FORMAT_SOAP) {
2642
		if (strchr(msg, '<')) {
2643
			doc = lasso_xml_parse_memory(msg, strlen(msg));
2644
			if (doc == NULL) {
2645
				rc = LASSO_MESSAGE_FORMAT_UNKNOWN;
2646
				goto cleanup;
2647
			}
2648
			root = xmlDocGetRootElement(doc);
2649

    
2650
			if (any || constraint == LASSO_MESSAGE_FORMAT_SOAP) {
2651
				gboolean is_soap = FALSE;
2652

    
2653
				is_soap = lasso_xml_is_soap(root);
2654
				if (is_soap) {
2655
					root = lasso_xml_get_soap_content(root);
2656
				}
2657
				rc = lasso_node_init_from_xml(node, root);
2658
				if (rc != 0) {
2659
					rc = LASSO_MESSAGE_FORMAT_XSCHEMA_ERROR;
2660
					goto cleanup;
2661

    
2662
				}
2663
				if (is_soap) {
2664
					rc = LASSO_MESSAGE_FORMAT_SOAP;
2665
					goto cleanup;
2666
				}
2667
				if (b64) {
2668
					lasso_release(msg);
2669
					rc = LASSO_MESSAGE_FORMAT_BASE64;
2670
					goto cleanup;
2671
				}
2672
				rc = LASSO_MESSAGE_FORMAT_XML;
2673
				goto cleanup;
2674
			}
2675
		}
2676
	}
2677

    
2678
	/* HTTP query CASE */
2679
	if (any || constraint == LASSO_MESSAGE_FORMAT_QUERY) {
2680
		if (strchr(msg, '&') || strchr(msg, '=')) {
2681
			/* XXX: detect SAML artifact messages to return a different status code ? */
2682
			if (lasso_node_init_from_query(node, msg) == FALSE) {
2683
				goto cleanup;
2684
			}
2685
			rc = LASSO_MESSAGE_FORMAT_QUERY;
2686
			goto cleanup;
2687
		}
2688
	}
2689

    
2690
cleanup:
2691
	if (doc_out) {
2692
		*doc_out = doc;
2693
		if (root_out) {
2694
			*root_out = root;
2695
		}
2696
	} else {
2697
		lasso_release_doc(doc);
2698
	}
2699
	return rc;
2700
}
2701

    
2702
/**
2703
 * lasso_node_init_from_message:
2704
 * @node: a #LassoNode (or derived class)
2705
 * @message: a Liberty message
2706
 *
2707
 * Parses @message and initialiazes @node fields with data from it.  Message
2708
 * type may be base64, SOAP, XML or query string, correct type is found
2709
 * automatically.
2710
 *
2711
 * Return value: a #LassoMessageFormat value.
2712
 **/
2713
LassoMessageFormat
2714
lasso_node_init_from_message(LassoNode *node, const char *message)
2715
{
2716
	return lasso_node_init_from_message_with_format(node, message, LASSO_MESSAGE_FORMAT_UNKNOWN, NULL, NULL);
2717
}
2718

    
2719
/**
2720
 * lasso_node_class_add_snippets:
2721
 * @klass: object class
2722
 * @snippets: array of XmlSnippet (NULL terminated)
2723
 **/
2724
void
2725
lasso_node_class_add_snippets(LassoNodeClass *klass, struct XmlSnippet *snippets)
2726
{
2727
	klass->node_data->snippets = snippets;
2728
}
2729

    
2730

    
2731
/**
2732
 * lasso_node_class_add_query_snippets:
2733
 * @klass: object class
2734
 * @snippets: array of QuerySnippet (NULL terminated)
2735
 **/
2736
void
2737
lasso_node_class_add_query_snippets(LassoNodeClass *klass, struct QuerySnippet *snippets)
2738
{
2739
	klass->node_data->query_snippets = snippets;
2740
}
2741

    
2742
/**
2743
 * lasso_node_class_set_nodename:
2744
 * @klass: object class
2745
 * @name: name for element node
2746
 **/
2747
void
2748
lasso_node_class_set_nodename(LassoNodeClass *klass, char *name)
2749
{
2750
	if (klass->node_data->node_name)
2751
		lasso_release(klass->node_data->node_name);
2752
	klass->node_data->node_name = g_strdup(name);
2753
}
2754

    
2755

    
2756
/**
2757
 * lasso_node_class_set_ns:
2758
 * @klass: object class
2759
 * @href: namespace uri
2760
 * @prefix: namespace prefix
2761
 **/
2762
void
2763
lasso_node_class_set_ns(LassoNodeClass *klass, char *href, char *prefix)
2764
{
2765
	if (klass->node_data->ns)
2766
		xmlFreeNs(klass->node_data->ns);
2767
	klass->node_data->ns = xmlNewNs(NULL, (xmlChar*)href, (xmlChar*)prefix);
2768
}
2769

    
2770
static void
2771
snippet_dump_any(gchar *key, gchar *value, xmlNode *xmlnode)
2772
{
2773
	if (! key)
2774
		return;
2775
	if (! value)
2776
		return;
2777
	/* element tree syntax for setting namespaces */
2778
	if (key && key[0] == '{') {
2779
		char *end = strchr(key, '}');
2780
		char *ns_uri;
2781
		xmlNs *ns;
2782
		if (! end) {
2783
			message(G_LOG_LEVEL_WARNING, "Invalid attribute name: %s", key);
2784
			return;
2785
		}
2786
		ns_uri = g_strndup(key+1, end-(key+1));
2787
		ns = get_or_define_ns(xmlnode, BAD_CAST ns_uri, NULL);
2788
		xmlSetNsProp(xmlnode, ns, BAD_CAST &end[1], BAD_CAST value);
2789
	} else {
2790
		xmlSetProp(xmlnode, BAD_CAST key, BAD_CAST value);
2791
	}
2792
}
2793

    
2794
static void
2795
apply_snippet_ns(struct XmlSnippet *snippet, xmlNode *xmlnode)
2796
{
2797
	xmlNs *ns;
2798

    
2799
	if (! xmlnode)
2800
		return;
2801
	if (snippet->ns_uri) {
2802
		if (! xmlnode->ns || !lasso_strisequal((char*)xmlnode->ns->href, (char*)snippet->ns_uri)) {
2803
			ns = get_or_define_ns(xmlnode, BAD_CAST snippet->ns_uri, BAD_CAST snippet->ns_name);
2804
			xmlSetNs(xmlnode, ns);
2805
		}
2806
		/* If not a any snippet, apply given Name, what about xsi:type ? */
2807
	}
2808
	if (! (snippet->type & SNIPPET_ANY) && ! lasso_strisempty(snippet->name) &&
2809
			lasso_strisnotequal((char*)xmlnode->name, (char*)snippet->name))
2810
		xmlNodeSetName(xmlnode, BAD_CAST snippet->name);
2811
}
2812

    
2813
static void
2814
lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, xmlNode *xmlnode,
2815
		struct XmlSnippet *snippets, gboolean lasso_dump)
2816
{
2817
	struct XmlSnippet *snippet;
2818
	GType g_type;
2819
	xmlNode *t;
2820
	GList *elem;
2821
	struct XmlSnippet *snippet_any_attribute = NULL;
2822

    
2823
	g_type = G_TYPE_FROM_CLASS(class);
2824

    
2825
	snippet = snippets;
2826
	while (snippet && snippet->name) {
2827
		void *value = NULL;
2828
		int int_value = 0;
2829
		gboolean bool_value = FALSE;
2830
		char *str = NULL;
2831
		gboolean optional = snippet->type & SNIPPET_OPTIONAL;
2832
		gboolean optional_neg = snippet->type & SNIPPET_OPTIONAL_NEG;
2833
		gboolean multiple = is_snippet_multiple(snippet);
2834

    
2835
		if (! snippet->offset && ! (snippet->type & SNIPPET_PRIVATE)) {
2836
			goto advance;
2837
		}
2838
		if (lasso_dump == FALSE && snippet->type & SNIPPET_LASSO_DUMP) {
2839
			goto advance;
2840
		}
2841
		if ((snippet->type & 0xff) == SNIPPET_ATTRIBUTE && (snippet->type & SNIPPET_ANY)) {
2842
			snippet_any_attribute = snippet;
2843
			goto advance;
2844
		}
2845
		/* special treatment for 1-* list of nodes, without we would serialize them twice */
2846
		if (multiple && (snippet->type & SNIPPET_JUMP_ON_MATCH && SNIPPET_JUMP_OFFSET(snippet->type) > 0)) {
2847
			snippet++;
2848
			continue;
2849
		}
2850

    
2851
		// convert input type to string if needed
2852
		if (snippet->type & SNIPPET_INTEGER) {
2853
			int_value = SNIPPET_STRUCT_MEMBER(int, node, g_type, snippet);
2854
			if (int_value == 0 && optional) {
2855
				goto advance;
2856
			}
2857
			if (int_value == -1 && optional_neg) {
2858
				goto advance;
2859
			}
2860
			str = g_strdup_printf("%i", int_value);
2861
		} else if (snippet->type & SNIPPET_BOOLEAN) {
2862
			bool_value = SNIPPET_STRUCT_MEMBER(gboolean, node, g_type, snippet);
2863
			if (bool_value == FALSE  && optional) {
2864
				goto advance;
2865
			}
2866
			str = bool_value ? "true" : "false";
2867
		} else {
2868
			value = SNIPPET_STRUCT_MEMBER(void *, node, g_type, snippet);
2869
			if (value == NULL) {
2870
				goto advance;
2871
			}
2872
			str = value;
2873
		}
2874

    
2875
		// output type
2876
		switch (snippet->type & 0xff) {
2877
			case SNIPPET_ATTRIBUTE:
2878
				if (snippet->ns_name) {
2879
					xmlNsPtr ns;
2880

    
2881
					ns = xmlNewNs(xmlnode, (xmlChar*)snippet->ns_uri, (xmlChar*)snippet->ns_name);
2882
					xmlSetNsProp(xmlnode, ns, (xmlChar*)snippet->name, (xmlChar*)str);
2883
				} else {
2884
					xmlSetProp(xmlnode, (xmlChar*)snippet->name, (xmlChar*)str);
2885
				}
2886
				break;
2887
			case SNIPPET_TEXT_CHILD:
2888
				xmlAddChild(xmlnode, xmlNewText((xmlChar*)str));
2889
				break;
2890
			case SNIPPET_NODE:
2891
				{
2892
					xmlNode *t2;
2893
					t2 = lasso_node_get_xmlNode(LASSO_NODE(value), lasso_dump);
2894
					apply_snippet_ns(snippet, t2);
2895
					xmlAddChild(xmlnode, t2);
2896
				} break;
2897
			case SNIPPET_CONTENT:
2898
				xmlNewTextChild(xmlnode, NULL,
2899
						(xmlChar*)snippet->name, (xmlChar*)str);
2900
				break;
2901
			case SNIPPET_NODE_IN_CHILD:
2902
				t = xmlNewTextChild(xmlnode, NULL, (xmlChar*)snippet->name, NULL);
2903
				xmlAddChild(t, lasso_node_get_xmlNode(
2904
							LASSO_NODE(value), lasso_dump));
2905
				break;
2906
			case SNIPPET_LIST_NODES:
2907
				elem = (GList *)value;
2908
				while (elem) {
2909
					xmlNode *subnode = lasso_node_get_xmlNode(
2910
							LASSO_NODE(elem->data), lasso_dump);
2911
					if (subnode) {
2912
						apply_snippet_ns(snippet, subnode);
2913
						xmlAddChild(xmlnode, subnode);
2914
					}
2915
					elem = g_list_next(elem);
2916
				}
2917
				break;
2918
			case SNIPPET_LIST_CONTENT:
2919
				/* sequence of simple elements (no children,
2920
				 * no attrs, just content) */
2921
				elem = (GList *)value;
2922
				while (elem) {
2923
					xmlNode *subnode;
2924
					subnode = xmlNewTextChild(xmlnode, NULL,
2925
							(xmlChar*)snippet->name,
2926
							(xmlChar*)(elem->data));
2927
					apply_snippet_ns(snippet, subnode);
2928
					elem = g_list_next(elem);
2929
				}
2930
				break;
2931
			case SNIPPET_LIST_XMLNODES:
2932
			case SNIPPET_EXTENSION:
2933
				elem = (GList *)value;
2934
				while (elem) {
2935
					xmlAddChild(xmlnode, xmlCopyNode(elem->data, 1));
2936
					elem = g_list_next(elem);
2937
				}
2938
				break;
2939
			case SNIPPET_XMLNODE:
2940
				xmlAddChild(xmlnode, xmlCopyNode((xmlNode *)value, 1));
2941
				break;
2942
			case SNIPPET_SIGNATURE:
2943
				lasso_node_add_signature_template(node, xmlnode, snippet);
2944
				break;
2945
			case SNIPPET_COLLECT_NAMESPACES:
2946
				break;
2947
			case SNIPPET_UNUSED1:
2948
				g_assert_not_reached();
2949
		}
2950
		if (snippet->type & SNIPPET_INTEGER) {
2951
			lasso_release(str);
2952
		}
2953
	advance:
2954
		if ((snippet->type & SNIPPET_JUMP_ON_MATCH) && SNIPPET_JUMP_OFFSET(snippet->type) > 0 && value) {
2955
			snippet += SNIPPET_JUMP_OFFSET(snippet->type);
2956
		} else if (!value && (snippet->type & SNIPPET_JUMP_ON_MISS) && SNIPPET_JUMP_OFFSET(snippet->type) > 0 && value) {
2957
			snippet += SNIPPET_JUMP_OFFSET(snippet->type);
2958
		} else {
2959
			snippet++;
2960
		}
2961
	}
2962

    
2963
	if (snippet_any_attribute) {
2964
		GHashTable *value = SNIPPET_STRUCT_MEMBER(GHashTable *, node, g_type,
2965
				snippet_any_attribute);
2966
		if (value) {
2967
			g_hash_table_foreach(value, (GHFunc)snippet_dump_any, xmlnode);
2968
		}
2969
	}
2970
}
2971

    
2972
static void
2973
lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
2974
		struct XmlSnippet *snippet_signature)
2975
{
2976
	LassoNodeClass *klass = NULL;
2977
	LassoNodeClassData *node_data = NULL;
2978
	LassoSignatureContext context;
2979
	char *id = NULL;
2980

    
2981
	node_data = lasso_legacy_get_signature_node_data(node, &klass);
2982
	if (! node_data)
2983
		return;
2984

    
2985
	if (node_data->sign_type_offset == 0)
2986
		return;
2987

    
2988
	context = lasso_node_get_signature(node);
2989
	if (! lasso_validate_signature_context(context))
2990
		if (lasso_legacy_extract_and_copy_signature_parameters(node, node_data))
2991
			context = lasso_node_get_signature(node);
2992

    
2993
	if (snippet_signature->offset) {
2994
		id = SNIPPET_STRUCT_MEMBER(char *, node, G_TYPE_FROM_CLASS(klass), snippet_signature);
2995
	}
2996

    
2997
	lasso_xmlnode_add_saml2_signature_template(xmlnode, context, id);
2998
}
2999

    
3000
static struct XmlSnippet*
3001
find_xml_snippet_by_name(LassoNode *node, char *name, LassoNodeClass **class_p)
3002
{
3003
	LassoNodeClass *class;
3004
	struct XmlSnippet *snippet;
3005

    
3006
	class = LASSO_NODE_GET_CLASS(node);
3007
	while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
3008
		for (snippet = class->node_data->snippets;
3009
				snippet && snippet->name && strcmp(snippet->name, name) != 0;
3010
				snippet++) ;
3011
		if (snippet && snippet->name) {
3012
			*class_p = class;
3013
			return snippet;
3014
		}
3015
		class = g_type_class_peek_parent(class);
3016
	}
3017
	*class_p = NULL;
3018
	return NULL;
3019
}
3020

    
3021
static gboolean
3022
find_path(LassoNode *node, char *path, LassoNode **value_node, LassoNodeClass **class_p, struct XmlSnippet **snippet)
3023
{
3024
	char *s, *t;
3025
	struct XmlSnippet *tsnippet = NULL;
3026
	LassoNode *tnode = node;
3027

    
3028
	*class_p = NULL;
3029
	s = path;
3030
	while (s) {
3031
		t = strchr(s, '/');
3032
		if (t) *t = 0;
3033
		tsnippet = find_xml_snippet_by_name(tnode, s, class_p);
3034
		if (t) {
3035
			tnode = SNIPPET_STRUCT_MEMBER(LassoNode *, tnode, G_TYPE_FROM_CLASS(*class_p),
3036
					tsnippet);
3037
			if (tnode == NULL)
3038
				return FALSE;
3039

    
3040
			s = t+1;
3041
		} else {
3042
			s = NULL;
3043
		}
3044
	}
3045

    
3046
	if (tsnippet == NULL)
3047
		return FALSE;
3048

    
3049
	*snippet = tsnippet;
3050
	*value_node = tnode;
3051
	return TRUE;
3052
}
3053

    
3054

    
3055
static char*
3056
get_value_by_path(LassoNode *node, char *path, struct XmlSnippet *xml_snippet)
3057
{
3058
	struct XmlSnippet *snippet;
3059
	LassoNode *value_node;
3060
	LassoNodeClass *class;
3061
	GType g_type;
3062

    
3063
	if (find_path(node, path, &value_node, &class, &snippet) != TRUE)
3064
		return NULL;
3065
	g_type = G_TYPE_FROM_CLASS(class);
3066

    
3067
	*xml_snippet = *snippet;
3068

    
3069
	if (snippet->type & SNIPPET_BOOLEAN) {
3070
		gboolean v = SNIPPET_STRUCT_MEMBER(gboolean, value_node, g_type, snippet);
3071
		return v ? g_strdup("true") : g_strdup("false");
3072
	} else if (snippet->type & SNIPPET_INTEGER) {
3073
		int v = SNIPPET_STRUCT_MEMBER(int, value_node, g_type, snippet);
3074
		return g_strdup_printf("%d", v);
3075
	} else if (snippet->type == SNIPPET_NODE) {
3076
		LassoNode *value = SNIPPET_STRUCT_MEMBER(LassoNode *, value_node, g_type, snippet);
3077
		return lasso_node_build_query(value);
3078
	} else if (snippet->type == SNIPPET_EXTENSION) {
3079
		/* convert all of the <lib:Extension> into a string, already
3080
		 * escaped for URI usage */
3081
		GList *value = SNIPPET_STRUCT_MEMBER(GList *, value_node, g_type, snippet);
3082
		xmlChar *s, *s2;
3083
		GString *result = g_string_new("");
3084
		while (value) {
3085
			xmlNode *t = value->data;
3086
			xmlNode *c;
3087

    
3088
			/* attributes */
3089
#if 0
3090
			xmlAttr *a;
3091
			for (a = t->properties; a; a = a->next) {
3092
				if (result->len)
3093
					g_string_append(result, "&");
3094
				s = xmlGetProp(t, a->name);
3095
				g_string_append(result, a->name);
3096
				g_string_append(result, "=");
3097
				s2 = xmlURIEscapeStr(s, NULL);
3098
				g_string_append(result, s2);
3099
				xmlFree(s2);
3100
				xmlFree(s);
3101
			}
3102
#endif
3103

    
3104
			/* children (only simple ones and 1-level deep) */
3105
			for (c = t->children; c; c = c->next) {
3106
				if (c->type != XML_ELEMENT_NODE)
3107
					continue;
3108
				if (c->children->type != XML_TEXT_NODE)
3109
					continue;
3110
				if (c->properties != NULL)
3111
					continue;
3112
				if (result->len)
3113
					g_string_append(result, "&");
3114
				g_string_append(result, (char*)c->name);
3115
				g_string_append(result, "=");
3116
				s = xmlNodeGetContent(c);
3117
				s2 = xmlURIEscapeStr(s, NULL);
3118
				g_string_append(result, (char*)s2);
3119
				xmlFree(s2);
3120
				xmlFree(s);
3121
			}
3122

    
3123
			value = g_list_next(value);
3124
		}
3125
		if (result->len == 0) {
3126
			lasso_release_gstring(result, TRUE);
3127
			return NULL;
3128
		}
3129
		return g_string_free(result, FALSE);
3130
	} else if (snippet->type == SNIPPET_LIST_CONTENT) {
3131
		/* not clear in spec; concat values with spaces */
3132
		GList *value = SNIPPET_STRUCT_MEMBER(GList *, value_node, g_type, snippet);
3133
		GString *result = g_string_new("");
3134
		while (value) {
3135
			result = g_string_append(result, (char*)value->data);
3136
			if (value->next)
3137
				result = g_string_append(result, " ");
3138
			value = value->next;
3139
		}
3140
		if (result->len == 0) {
3141
			lasso_release_gstring(result, TRUE);
3142
			return NULL;
3143
		}
3144
		return g_string_free(result, FALSE);
3145
	} else {
3146
		char *value = SNIPPET_STRUCT_MEMBER(char *, value_node, g_type, snippet);
3147
		if (value == NULL) return NULL;
3148
		return g_strdup(value);
3149
	}
3150
	return NULL;
3151
}
3152

    
3153
static gboolean
3154
set_value_at_path(LassoNode *node, char *path, char *query_value)
3155
{
3156
	struct XmlSnippet *snippet;
3157
	LassoNode *value_node;
3158
	LassoNodeClass *class;
3159
	GType g_type;
3160
	void *value;
3161

    
3162
	if (find_path(node, path, &value_node, &class, &snippet) != TRUE)
3163
		return FALSE;
3164
	g_type = G_TYPE_FROM_CLASS(class);
3165

    
3166
	value = SNIPPET_STRUCT_MEMBER_P(value_node, g_type, snippet);
3167

    
3168
	if (snippet->type & SNIPPET_INTEGER) {
3169
		int val = atoi(query_value);
3170
		(*(int*)value) = val;
3171
	} else if (snippet->type & SNIPPET_BOOLEAN) {
3172
		int val = (strcmp(query_value, "true") == 0);
3173
		(*(int*)value) = val;
3174
	} else if (snippet->type == SNIPPET_NODE) {
3175
		LassoNode *v = *(LassoNode**)value;
3176
		if (v == NULL) {
3177
			message(G_LOG_LEVEL_CRITICAL, "building node from query; unknown subnode");
3178
			g_assert_not_reached();
3179
		}
3180
		LASSO_NODE_GET_CLASS(v)->init_from_query(v, &query_value);
3181
	} else if (snippet->type == SNIPPET_LIST_CONTENT) {
3182
		char **elems = g_strsplit(query_value, " ", 0);
3183
		int i;
3184
		GList *l = NULL;
3185
		for (i = 0; elems[i]; i++) {
3186
			l = g_list_append(l, g_strdup(elems[i]));
3187
		}
3188
		g_strfreev(elems);
3189
		(*(GList**)value) = l;
3190
	} else {
3191
		(*(char**)value) = g_strdup(query_value);
3192
	}
3193

    
3194
	return TRUE;
3195
}
3196

    
3197

    
3198
gchar*
3199
lasso_node_build_query_from_snippets(LassoNode *node)
3200
{
3201
	int i;
3202
	char path[100];
3203
	char *v;
3204
	GString *s;
3205
	xmlChar *t;
3206
	LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
3207
	struct QuerySnippet *query_snippets = NULL;
3208
	struct XmlSnippet xml_snippet;
3209

    
3210
	while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
3211
		if (class->node_data && class->node_data->query_snippets) {
3212
			query_snippets = class->node_data->query_snippets;
3213
			break;
3214
		}
3215
		class = g_type_class_peek_parent(class);
3216
	}
3217
	if (query_snippets == NULL)
3218
		return NULL;
3219

    
3220
	s = g_string_sized_new(2000);
3221

    
3222
	for (i=0; query_snippets[i].path; i++) {
3223
		g_strlcpy(path, query_snippets[i].path, 100);
3224
		v = get_value_by_path(node, path, &xml_snippet);
3225
		if (v && xml_snippet.type == SNIPPET_EXTENSION) {
3226
			if (s->len)
3227
				g_string_append(s, "&");
3228
			g_string_append(s, v);
3229
			lasso_release(v);
3230
			continue;
3231
		}
3232
		if (v) {
3233
			char *field_name = query_snippets[i].field_name;
3234
			if (field_name == NULL)
3235
				field_name = query_snippets[i].path;
3236
			if (s->len)
3237
				g_string_append(s, "&");
3238
			g_string_append(s, field_name);
3239
			g_string_append(s, "=");
3240
			t = xmlURIEscapeStr((xmlChar*)v, NULL);
3241
			g_string_append(s, (char*)t);
3242
			xmlFree(t);
3243
		}
3244
		if (v)
3245
			lasso_release(v);
3246
	}
3247

    
3248
	return g_string_free(s, FALSE);
3249
}
3250

    
3251

    
3252
gboolean
3253
lasso_node_init_from_query_fields(LassoNode *node, char **query_fields)
3254
{
3255
	int i, j;
3256
	char *field, *t;
3257
	LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
3258
	struct QuerySnippet *query_snippets = NULL;
3259
	gboolean has_extension = FALSE;
3260

    
3261
	while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
3262
		if (class->node_data && class->node_data->query_snippets) {
3263
			query_snippets = class->node_data->query_snippets;
3264
			break;
3265
		}
3266
		class = g_type_class_peek_parent(class);
3267
	}
3268
	if (query_snippets == NULL)
3269
		return FALSE;
3270

    
3271
	for (i = 0; (field = query_fields[i]); i++) {
3272
		t = strchr(field, '=');
3273
		if (t == NULL)
3274
			continue;
3275
		*t = 0;
3276

    
3277
		for (j=0; query_snippets[j].path; j++) {
3278
			char *field_name = query_snippets[j].field_name;
3279
			char path[100];
3280

    
3281
			g_strlcpy(path, query_snippets[j].path, 100);
3282

    
3283
			if (field_name == NULL)
3284
				field_name = query_snippets[j].path;
3285
			if (strcmp(field_name, "Extension") == 0) {
3286
				has_extension = TRUE;
3287
				continue;
3288
			}
3289
			if (strcmp(field, field_name) != 0)
3290
				continue;
3291
			set_value_at_path(node, path, t+1);
3292
			break;
3293
		}
3294
		if (query_snippets[j].path == NULL && has_extension &&
3295
				strcmp(field, "SigAlg") != 0 && strcmp(field, "Signature") != 0) {
3296
			/* got to the end without finding anything; and has
3297
			 * Extension; build it */
3298
			struct XmlSnippet *extension_snippet;
3299
			LassoNode *value_node;
3300
			LassoNodeClass *class;
3301
			GList **value;
3302
			xmlNode *xmlnode, *xmlchild;
3303
			if (find_path(node, "Extension", &value_node, &class, &extension_snippet) == TRUE) {
3304
				GType g_type = G_TYPE_FROM_CLASS(class);
3305
				value = SNIPPET_STRUCT_MEMBER_P(value_node, g_type,
3306
						extension_snippet);
3307
				if (*value) {
3308
					xmlnode = (*value)->data;
3309
				} else {
3310
					xmlnode = xmlNewNode(xmlNewNs(NULL,
3311
								(xmlChar*)LASSO_LIB_HREF,
3312
								(xmlChar*)LASSO_LIB_PREFIX),
3313
							(xmlChar*)"Extension");
3314
				}
3315
				xmlchild = xmlNewNode(NULL, (xmlChar*)field);
3316
				xmlAddChild(xmlchild, xmlNewText((xmlChar*)t+1));
3317
				xmlAddChild(xmlnode, xmlchild);
3318
				if (! *value)
3319
					*value = g_list_append(*value, xmlnode);
3320
			}
3321
		}
3322
		*t = '=';
3323
	}
3324

    
3325
	return TRUE;
3326
}
3327

    
3328
gboolean
3329
lasso_node_init_from_saml2_query_fields(LassoNode *node, char **query_fields, G_GNUC_UNUSED char **relay_state)
3330
{
3331
	int i;
3332
	char *field, *t;
3333
	char *req = NULL;
3334
	char *enc = NULL;
3335
	gboolean rc;
3336

    
3337
	for (i=0; (field=query_fields[i]); i++) {
3338
		t = strchr(field, '=');
3339
		if (t == NULL)
3340
			continue;
3341
		*t = 0;
3342
		if (strcmp(field, LASSO_SAML2_FIELD_ENCODING) == 0) {
3343
			enc = t+1;
3344
			continue;
3345
		}
3346
		if (strcmp(field, LASSO_SAML2_FIELD_REQUEST) == 0 || strcmp(field, LASSO_SAML2_FIELD_RESPONSE) == 0) {
3347
			req = t+1;
3348
			continue;
3349
		}
3350
	}
3351

    
3352
	if (enc && strcmp(enc, LASSO_SAML2_DEFLATE_ENCODING) != 0) {
3353
		/* unknown encoding */
3354
		message(G_LOG_LEVEL_CRITICAL, "Unknown URL encoding: %s", enc);
3355
		return FALSE;
3356
	}
3357

    
3358
	if (req == NULL) {
3359
		return FALSE;
3360
	}
3361

    
3362
	rc = lasso_node_init_from_deflated_query_part(node, req);
3363
	if (rc == FALSE) {
3364
		return rc;
3365
	}
3366

    
3367
	return TRUE;
3368
}
3369

    
3370
static void
3371
xmlDeclareNs(xmlNode *root_node, xmlNode *node)
3372
{
3373
	xmlNs *ns;
3374
	xmlNode *t;
3375

    
3376
	if (strcmp((char*)node->name, "Signature") == 0)
3377
		return;
3378

    
3379
	for (ns = node->nsDef; ns; ns = ns->next) {
3380
		if (ns->prefix && strcmp((char*)ns->prefix, "xsi") != 0) {
3381
			xmlNewNs(root_node, ns->href, ns->prefix);
3382
		}
3383
	}
3384
	for (t = node->children; t; t = t->next) {
3385
		if (t->type == XML_ELEMENT_NODE) {
3386
			xmlDeclareNs(root_node, t);
3387
		}
3388
	}
3389
}
3390

    
3391
static inline int
3392
sameNs(xmlNs *ns1, xmlNs *ns2)
3393
{
3394
	/* this checks ns->prefix instead of ns->href so it is possible to
3395
	 * merge down to an earlier version of liberty namespace
3396
	 */
3397
	return (ns1 == NULL && ns2 == NULL) || (
3398
			ns1 && ns2 && ns1->prefix && ns2->prefix &&
3399
			strcmp((char*)ns1->prefix, (char*)ns2->prefix) == 0 &&
3400
			strcmp((char*)ns1->href, (char*)ns2->href) == 0);
3401
}
3402

    
3403
static void
3404
xmlPropUseNsDef(xmlNs *ns, xmlNode *node)
3405
{
3406
	xmlAttr *attr;
3407

    
3408
	for (attr = node->properties; attr; attr = attr->next) {
3409
		if (sameNs(ns, attr->ns)) {
3410
			attr->ns = ns;
3411
		}
3412
	}
3413
}
3414

    
3415
static void
3416
xmlUseNsDef(xmlNs *ns, xmlNode *node)
3417
{
3418
	xmlNode *t;
3419
	xmlNs *ns2;
3420
	xmlNs *ns3 = NULL;
3421

    
3422
	xmlPropUseNsDef(ns, node);
3423
	if (sameNs(ns, node->ns)) {
3424
		node->ns = ns;
3425
	}
3426

    
3427
	for (t = node->children; t; t = t->next) {
3428
		if (t->type == XML_ELEMENT_NODE)
3429
			xmlUseNsDef(ns, t);
3430
	}
3431

    
3432
	if (sameNs(node->nsDef, ns)) {
3433
		ns3 = node->nsDef;
3434
		node->nsDef = node->nsDef->next;
3435
		xmlFreeNs(ns3);
3436
	} else if (node->nsDef) {
3437
		for (ns2 = node->nsDef; ns2->next; ns2 = ns2->next) {
3438
			if (sameNs(ns2->next, ns)) {
3439
				ns3 = ns2->next;
3440
				ns2->next = ns2->next->next;
3441
				xmlFreeNs(ns3);
3442
				if (ns2->next == NULL)
3443
					break;
3444
			}
3445
		}
3446
	}
3447
}
3448

    
3449
/**
3450
 * xmlCleanNs
3451
 * @root_node: the root #xmlNode where to start the cleaning.
3452
 *
3453
 * xmlCleanNs removes duplicate xml namespace declarations and merge them on
3454
 * the @root_node.
3455
 **/
3456
void
3457
xmlCleanNs(xmlNode *root_node)
3458
{
3459
	xmlNs *ns;
3460
	xmlNode *t;
3461

    
3462
	for (t = root_node->children; t; t = t->next)
3463
		if (t->type == XML_ELEMENT_NODE)
3464
			xmlDeclareNs(root_node, t);
3465

    
3466
	for (ns = root_node->nsDef; ns; ns = ns->next) {
3467
		for (t = root_node->children; t; t = t->next)
3468
			if (t->type == XML_ELEMENT_NODE)
3469
				xmlUseNsDef(ns, t);
3470
	}
3471
}
3472

    
3473
void
3474
xml_insure_namespace(xmlNode *xmlnode, xmlNs *ns, gboolean force, gchar *ns_href, gchar *ns_prefix)
3475
{
3476
	xmlNode *t = xmlnode->children;
3477

    
3478
	if (ns == NULL) {
3479
		for (ns = xmlnode->nsDef; ns; ns = ns->next) {
3480
			if (ns->href && lasso_strisequal((gchar *)ns->href,ns_href)) {
3481
				break;
3482
			}
3483
		}
3484
		if (ns == NULL) {
3485
			ns = xmlNewNs(xmlnode, (xmlChar*)ns_href, (xmlChar*)ns_prefix);
3486
		}
3487
	}
3488

    
3489
	xmlSetNs(xmlnode, ns);
3490
	while (t) {
3491
		if (t->type == XML_ELEMENT_NODE && (force == TRUE || t->ns == NULL)) {
3492
			xml_insure_namespace(t, ns, force, NULL, NULL);
3493
		}
3494
		t = t->next;
3495
	}
3496
}
3497

    
3498
/**
3499
 * lasso_node_get_xmlnode_for_any_type:
3500
 * @node: a #LassoNode.
3501
 * @xmlnode: the #xmlNode returned.
3502
 *
3503
 * Return value: a xmlNode completed with the content of the produced by the get_xmlNode virtual
3504
 * method of the parent class.
3505
 */
3506
xmlNode*
3507
lasso_node_get_xmlnode_for_any_type(LassoNode *node, xmlNode *cur)
3508
{
3509
	xmlNode *original_xmlnode;
3510

    
3511
	original_xmlnode = lasso_node_get_original_xmlnode(node);
3512
	if (cur) {
3513
		if (original_xmlnode) {
3514
			xmlNode *children = xmlCopyNodeList(original_xmlnode->children);
3515
			xmlAttr *attrs = xmlCopyPropList(cur, original_xmlnode->properties);
3516
			if (cur->properties == NULL) {
3517
				cur->properties = attrs;
3518
			} else {
3519
				xmlAttr *it = cur->properties;
3520
				while (it->next) {
3521
					it = it->next;
3522
				}
3523
				it->next = attrs;
3524
			}
3525
			xmlAddChildList(cur, children);
3526
			return cur;
3527
		} else {
3528
			return cur;
3529
		}
3530
	} else {
3531
		if (original_xmlnode) {
3532
			return xmlCopyNode(original_xmlnode, 1);
3533
		} else {
3534
			return cur;
3535
		}
3536
	}
3537
}
3538

    
3539
/**
3540
 * lasso_node_get_name:
3541
 * @node: a #LassoNode
3542
 *
3543
 * Return the XML element name for this object, the one that would be used in the XML dump of this
3544
 * object.
3545
 *
3546
 * Return value: the name of the object, the value must not be stored.
3547
 */
3548
const char*
3549
lasso_node_get_name(LassoNode *node)
3550
{
3551
	struct _CustomElement *custom_element;
3552
	LassoNodeClass *klass;
3553
	g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
3554

    
3555
	custom_element = _lasso_node_get_custom_element(node);
3556
	if (custom_element && custom_element->nodename) {
3557
		return custom_element->nodename;
3558
	}
3559
	klass = LASSO_NODE_GET_CLASS(node);
3560
	return klass->node_data->node_name;
3561
}
3562

    
3563
/**
3564
 * lasso_node_get_name:
3565
 * @node: a #LassoNode
3566
 *
3567
 * Return the XML element name for this object, the one that would be used in the XML dump of this
3568
 * object.
3569
 *
3570
 * Return value: the name of the object, the value must not be stored.
3571
 */
3572
const char*
3573
lasso_node_get_namespace(LassoNode *node)
3574
{
3575
	struct _CustomElement *custom_element;
3576
	LassoNodeClass *klass;
3577
	g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
3578

    
3579
	custom_element = _lasso_node_get_custom_element(node);
3580
	if (custom_element && custom_element->nodename) {
3581
		return custom_element->href;
3582
	}
3583
	klass = LASSO_NODE_GET_CLASS(node);
3584
	if (klass->node_data && klass->node_data->ns)
3585
		return (const char*)klass->node_data->ns->href;
3586
	return NULL;
3587
}
3588

    
3589

    
3590
/**
3591
 * lasso_node_export_to_saml2_query:
3592
 * @node: the #LassoNode object to pass as a query
3593
 * @param_name: the key value for the query string parameter
3594
 * @url:(allow-none): an optional URL to prepend to the query string
3595
 * @key:(allow-none): a #LassoKey object
3596
 *
3597
 * Export a node as signed query string, the node must support serialization as a query.
3598
 *
3599
 * Return value: an HTTP URL or query string if successful, NULL otherwise.
3600
 */
3601
char*
3602
lasso_node_export_to_saml2_query(LassoNode *node, const char *param_name, const char *url,
3603
		LassoKey *key)
3604
{
3605
	char *value = NULL, *query = NULL, *signed_query = NULL, *result = NULL;
3606
	xmlChar *encoded_param = NULL;
3607

    
3608
	value = lasso_node_build_deflated_query(node);
3609
	if (! value)
3610
		goto cleanup;
3611
	encoded_param = xmlURIEscapeStr(BAD_CAST param_name, NULL);
3612
	if (! encoded_param)
3613
		goto cleanup;
3614
	query = g_strdup_printf("%s=%s", encoded_param, value);
3615
	if (! query)
3616
		goto cleanup;
3617
	if (LASSO_IS_KEY(key)) {
3618
		signed_query = lasso_key_query_sign(key, query);
3619
	} else {
3620
		lasso_transfer_string(signed_query, query);
3621
	}
3622
	if (! signed_query)
3623
		goto cleanup;
3624
	if (url) {
3625
		result = lasso_concat_url_query(url, signed_query);
3626
	} else {
3627
		lasso_transfer_string(result, signed_query);
3628
	}
3629

    
3630
cleanup:
3631
	lasso_release_string(value);
3632
	lasso_release_xml_string(encoded_param);
3633
	lasso_release_string(query);
3634
	lasso_release_string(signed_query);
3635
	return result;
3636
}
3637

    
3638
/**
3639
 * lasso_node_new_from_saml2_query:
3640
 * @url_or_qs: an URL containing a query string or a query string only
3641
 * @param_name: the key value for the query string parameter to extract as a #LassoNode.
3642
 * @key:(allow-none): a #LassoKey object
3643
 *
3644
 * Verify the signature on a SAML-2 encoded query string and return the encoded node.
3645
 *
3646
 * Return value: a newly build #LassoNode if successful, NULL otherwise.
3647
 */
3648
LassoNode*
3649
lasso_node_new_from_saml2_query(const char *url_or_qs, const char *param_name, LassoKey *key)
3650
{
3651
	char *needle = NULL;
3652
	LassoNode *result = NULL;
3653

    
3654
	if (! url_or_qs || ! param_name)
3655
		return NULL;
3656
	needle = strchr(url_or_qs, '?');
3657
	if (needle) {
3658
		url_or_qs = (const char*)(needle+1);
3659
	}
3660
	if (key) {
3661
		goto_cleanup_if_fail(lasso_key_query_verify(key, url_or_qs) == 0);
3662
	}
3663
cleanup:
3664
	return result;
3665
}