Coverage Report

Created: 2026-08-31 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xmlsec/src/xpath.c
Line
Count
Source
1
/**
2
 * XML Security Library (http://www.aleksey.com/xmlsec).
3
 *
4
 * This is free software; see the Copyright file in the source distribution for precise wording.
5
 *
6
 * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
7
 */
8
/**
9
 * @addtogroup xmlsec_core_transforms
10
 * @brief XPath transform implementation.
11
 */
12
#include "globals.h"
13
14
#include <stdlib.h>
15
#include <string.h>
16
17
#include <libxml/tree.h>
18
#include <libxml/xpath.h>
19
#include <libxml/xpathInternals.h>
20
#include <libxml/xpointer.h>
21
22
#include <xmlsec/xmlsec.h>
23
#include <xmlsec/xmltree.h>
24
#include <xmlsec/keys.h>
25
#include <xmlsec/list.h>
26
#include <xmlsec/transforms.h>
27
#include <xmlsec/errors.h>
28
29
#include "cast_helpers.h"
30
31
/**
32
 * @brief Implements the XPath here() function.
33
 * @details The implementation of XPath "here()" function.
34
 * See xmlXPtrHereFunction() in xpointer.c. the only change is that
35
 * we return NodeSet instead of NodeInterval.
36
 * @param ctxt the pointer to XPath context.
37
 * @param nargs the arguments number.
38
 */
39
static void
40
0
xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
41
0
    xmlXPathObjectPtr obj;
42
43
0
    CHECK_ARITY(0);
44
45
0
    if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) {
46
0
        XP_ERROR(XPTR_SYNTAX_ERROR);
47
0
    }
48
0
    obj = xmlXPathNewNodeSet(ctxt->context->here);
49
0
    if(obj == NULL) {
50
0
        XP_ERROR(XPATH_MEMORY_ERROR);
51
0
    }
52
0
    valuePush(ctxt, obj);
53
0
}
54
55
/******************************************************************************
56
 *
57
 * XPath/XPointer data
58
 *
59
  *****************************************************************************/
60
typedef struct _xmlSecXPathData                 xmlSecXPathData,
61
                                                *xmlSecXPathDataPtr;
62
typedef enum {
63
    xmlSecXPathDataTypeXPath,
64
    xmlSecXPathDataTypeXPath2,
65
    xmlSecXPathDataTypeXPointer
66
} xmlSecXPathDataType;
67
68
struct _xmlSecXPathData {
69
    xmlSecXPathDataType                 type;
70
    xmlXPathContextPtr                  ctx;
71
    xmlChar*                            expr;
72
    xmlSecNodeSetOp                     nodeSetOp;
73
    xmlSecNodeSetType                   nodeSetType;
74
};
75
76
static xmlSecXPathDataPtr       xmlSecXPathDataCreate           (xmlSecXPathDataType type);
77
static void                     xmlSecXPathDataDestroy          (xmlSecXPathDataPtr data);
78
static int                      xmlSecXPathDataSetExpr          (xmlSecXPathDataPtr data,
79
                                                                 const xmlChar* expr);
80
static int                      xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data,
81
                                                                 xmlNodePtr node);
82
static int                      xmlSecXPathDataNodeRead         (xmlSecXPathDataPtr data,
83
                                                                 xmlNodePtr node);
84
static xmlSecNodeSetPtr         xmlSecXPathDataExecute          (xmlSecXPathDataPtr data,
85
                                                                 xmlDocPtr doc,
86
                                                                 xmlNodePtr hereNode);
87
88
static xmlSecXPathDataPtr
89
6.48k
xmlSecXPathDataCreate(xmlSecXPathDataType type) {
90
6.48k
    xmlSecXPathDataPtr data;
91
92
6.48k
    data = (xmlSecXPathDataPtr) xmlMalloc(sizeof(xmlSecXPathData));
93
6.48k
    if(data == NULL) {
94
0
        xmlSecMallocError(sizeof(xmlSecXPathData), NULL);
95
0
        return(NULL);
96
0
    }
97
6.48k
    memset(data, 0, sizeof(xmlSecXPathData));
98
99
6.48k
    data->type = type;
100
6.48k
    data->nodeSetType = xmlSecNodeSetTree;
101
102
    /* create xpath or xpointer context */
103
6.48k
    switch(data->type) {
104
0
    case xmlSecXPathDataTypeXPath:
105
0
    case xmlSecXPathDataTypeXPath2:
106
0
        data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */
107
0
        if(data->ctx == NULL) {
108
0
            xmlSecXmlError("xmlXPathNewContext", NULL);
109
0
            xmlSecXPathDataDestroy(data);
110
0
            return(NULL);
111
0
        }
112
0
        break;
113
6.48k
    case xmlSecXPathDataTypeXPointer:
114
6.48k
        data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */
115
6.48k
        if(data->ctx == NULL) {
116
0
            xmlSecXmlError("xmlXPathNewContext", NULL);
117
0
            xmlSecXPathDataDestroy(data);
118
0
            return(NULL);
119
0
        }
120
6.48k
        break;
121
6.48k
    }
122
123
6.48k
    return(data);
124
6.48k
}
125
126
static void
127
6.48k
xmlSecXPathDataDestroy(xmlSecXPathDataPtr data) {
128
6.48k
    xmlSecAssert(data != NULL);
129
130
6.48k
    if(data->expr != NULL) {
131
6.48k
        xmlFree(data->expr);
132
6.48k
    }
133
6.48k
    if(data->ctx != NULL) {
134
6.48k
        xmlXPathFreeContext(data->ctx);
135
6.48k
    }
136
6.48k
    memset(data, 0, sizeof(xmlSecXPathData));
137
6.48k
    xmlFree(data);
138
6.48k
}
139
140
static int
141
6.48k
xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data, const xmlChar* expr) {
142
6.48k
    xmlSecAssert2(data != NULL, -1);
143
6.48k
    xmlSecAssert2(data->expr == NULL, -1);
144
6.48k
    xmlSecAssert2(data->ctx != NULL, -1);
145
6.48k
    xmlSecAssert2(expr != NULL, -1);
146
147
6.48k
    data->expr = xmlStrdup(expr);
148
6.48k
    if(data->expr == NULL) {
149
0
        xmlSecStrdupError(expr, NULL);
150
0
        return(-1);
151
0
    }
152
6.48k
    return(0);
153
6.48k
}
154
155
156
static int
157
6.48k
xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, xmlNodePtr node) {
158
6.48k
    xmlNodePtr cur;
159
6.48k
    xmlNsPtr ns;
160
6.48k
    int ret;
161
162
6.48k
    xmlSecAssert2(data != NULL, -1);
163
6.48k
    xmlSecAssert2(data->ctx != NULL, -1);
164
6.48k
    xmlSecAssert2(node != NULL, -1);
165
166
    /* register namespaces */
167
34.3k
    for(cur = node; cur != NULL; cur = cur->parent) {
168
40.8k
        for(ns = cur->nsDef; ns != NULL; ns = ns->next) {
169
            /* check that we have no other namespace with same prefix already */
170
12.9k
            if((ns->prefix != NULL) && (xmlXPathNsLookup(data->ctx, ns->prefix) == NULL)){
171
165
                ret = xmlXPathRegisterNs(data->ctx, ns->prefix, ns->href);
172
165
                if(ret != 0) {
173
0
                    xmlSecXmlError2("xmlXPathRegisterNs", NULL,
174
0
                                    "prefix=%s", xmlSecErrorsSafeString(ns->prefix));
175
0
                    return(-1);
176
0
                }
177
165
            }
178
12.9k
        }
179
27.8k
    }
180
181
6.48k
    return(0);
182
6.48k
}
183
184
static int
185
0
xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data, xmlNodePtr node) {
186
0
    int ret;
187
188
0
    xmlSecAssert2(data != NULL, -1);
189
0
    xmlSecAssert2(data->expr == NULL, -1);
190
0
    xmlSecAssert2(data->ctx != NULL, -1);
191
0
    xmlSecAssert2(node != NULL, -1);
192
193
0
    ret = xmlSecXPathDataRegisterNamespaces (data, node);
194
0
    if(ret < 0) {
195
0
        xmlSecInternalError("xmlSecXPathDataRegisterNamespaces", NULL);
196
0
        return(-1);
197
0
    }
198
199
    /* read node content and set expr */
200
0
    data->expr = xmlNodeGetContent(node);
201
0
    if(data->expr == NULL) {
202
0
        xmlSecInvalidNodeContentError(node, NULL, "empty");
203
0
        return(-1);
204
0
    }
205
206
0
    return(0);
207
0
}
208
209
static xmlSecNodeSetPtr
210
6.48k
xmlSecXPathDataExecute(xmlSecXPathDataPtr data, xmlDocPtr doc, xmlNodePtr hereNode) {
211
6.48k
    xmlXPathObjectPtr xpathObj = NULL;
212
6.48k
    xmlSecNodeSetPtr nodes;
213
214
6.48k
    xmlSecAssert2(data != NULL, NULL);
215
6.48k
    xmlSecAssert2(data->expr != NULL, NULL);
216
6.48k
    xmlSecAssert2(data->ctx != NULL, NULL);
217
6.48k
    xmlSecAssert2(doc != NULL, NULL);
218
6.48k
    xmlSecAssert2(hereNode != NULL, NULL);
219
220
    /* do not forget to set the doc */
221
6.48k
    data->ctx->doc = doc;
222
223
    /* here function works only on the same document */
224
6.48k
    if(hereNode->doc == doc) {
225
6.48k
        data->ctx->here = hereNode;
226
6.48k
        data->ctx->xptr = 1;
227
6.48k
        xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", xmlSecXPathHereFunction);
228
6.48k
    } else {
229
        /* clear any stale "here" node/function left over from a previous
230
         * execution against another document */
231
0
        data->ctx->here = NULL;
232
0
        xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", NULL);
233
0
    }
234
235
    /* execute xpath or xpointer expression */
236
6.48k
    switch(data->type) {
237
0
    case xmlSecXPathDataTypeXPath:
238
0
    case xmlSecXPathDataTypeXPath2:
239
0
        xpathObj = xmlXPathEvalExpression(data->expr, data->ctx);
240
0
        if(xpathObj == NULL) {
241
0
            xmlSecXmlError2("xmlXPathEvalExpression", NULL,
242
0
                            "expr=%s", xmlSecErrorsSafeString(data->expr));
243
0
            return(NULL);
244
0
        }
245
0
        break;
246
6.48k
    case xmlSecXPathDataTypeXPointer:
247
6.48k
        xpathObj = xmlXPtrEval(data->expr, data->ctx);
248
6.48k
        if(xpathObj == NULL) {
249
4.38k
            xmlSecXmlError2("xmlXPtrEval", NULL,
250
4.38k
                            "expr=%s", xmlSecErrorsSafeString(data->expr));
251
4.38k
            return(NULL);
252
4.38k
        }
253
2.09k
        break;
254
2.09k
    default:
255
0
        xmlSecInternalError("Invalid XPath transform type", NULL);
256
0
        return(NULL);
257
6.48k
    }
258
259
    /* sometimes LibXML2 returns an empty nodeset or just NULL, we want
260
    to reserve NULL for our own purposes so we simply create an empty
261
    node set here */
262
2.09k
    if(xpathObj->nodesetval == NULL) {
263
0
        xpathObj->nodesetval = xmlXPathNodeSetCreate(NULL);
264
0
        if(xpathObj->nodesetval == NULL) {
265
0
            xmlXPathFreeObject(xpathObj);
266
0
            xmlSecXmlError2("xmlXPathNodeSetCreate", NULL,
267
0
                            "expr=%s", xmlSecErrorsSafeString(data->expr));
268
0
            return(NULL);
269
0
        }
270
0
    }
271
272
2.09k
    nodes = xmlSecNodeSetCreate(doc, xpathObj->nodesetval, data->nodeSetType);
273
2.09k
    if(nodes == NULL) {
274
0
        xmlSecInternalError2("xmlSecNodeSetCreate", NULL,
275
0
            "type=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(data->nodeSetType));
276
0
        xmlXPathFreeObject(xpathObj);
277
0
        return(NULL);
278
0
    }
279
2.09k
    xpathObj->nodesetval = NULL;
280
2.09k
    xmlXPathFreeObject(xpathObj);
281
282
2.09k
    return(nodes);
283
2.09k
}
284
285
286
/******************************************************************************
287
 *
288
 * XPath data list
289
 *
290
  *****************************************************************************/
291
#define xmlSecXPathDataListId   \
292
6.48k
        xmlSecXPathDataListGetKlass()
293
static xmlSecPtrListId  xmlSecXPathDataListGetKlass             (void);
294
static xmlSecNodeSetPtr xmlSecXPathDataListExecute              (xmlSecPtrListPtr dataList,
295
                                                                 xmlDocPtr doc,
296
                                                                 xmlNodePtr hereNode,
297
                                                                 xmlSecNodeSetPtr nodes);
298
299
static xmlSecPtrListKlass xmlSecXPathDataListKlass = {
300
    BAD_CAST "xpath-data-list",
301
    NULL,                                               /* xmlSecPtrDuplicateItemMethod duplicateItem; */
302
    (xmlSecPtrDestroyItemMethod)xmlSecXPathDataDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */
303
    NULL,                                               /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
304
    NULL,                                               /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
305
};
306
307
static xmlSecPtrListId
308
32.4k
xmlSecXPathDataListGetKlass(void) {
309
32.4k
    return(&xmlSecXPathDataListKlass);
310
32.4k
}
311
312
static xmlSecNodeSetPtr
313
xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList, xmlDocPtr doc,
314
6.48k
                           xmlNodePtr hereNode, xmlSecNodeSetPtr nodes) {
315
6.48k
    xmlSecXPathDataPtr data;
316
6.48k
    xmlSecNodeSetPtr res, tmp, tmp2;
317
6.48k
    xmlSecSize pos;
318
319
6.48k
    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), NULL);
320
6.48k
    xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, NULL);
321
6.48k
    xmlSecAssert2(doc != NULL, NULL);
322
6.48k
    xmlSecAssert2(hereNode != NULL, NULL);
323
324
6.48k
    res = nodes;
325
8.58k
    for(pos = 0; pos < xmlSecPtrListGetSize(dataList); ++pos) {
326
6.48k
        data = (xmlSecXPathDataPtr)xmlSecPtrListGetItem(dataList, pos);
327
6.48k
        if(data == NULL) {
328
0
            xmlSecInternalError2("xmlSecPtrListGetItem", NULL, "pos=" XMLSEC_SIZE_FMT, pos);
329
0
            if((res != NULL) && (res != nodes)) {
330
0
                xmlSecNodeSetDestroy(res);
331
0
            }
332
0
            return(NULL);
333
0
        }
334
335
6.48k
        tmp = xmlSecXPathDataExecute(data, doc, hereNode);
336
6.48k
        if(tmp == NULL) {
337
4.38k
            xmlSecInternalError("xmlSecXPathDataExecute", NULL);
338
4.38k
            if((res != NULL) && (res != nodes)) {
339
0
                xmlSecNodeSetDestroy(res);
340
0
            }
341
4.38k
            return(NULL);
342
4.38k
        }
343
344
2.09k
        tmp2 = xmlSecNodeSetAdd(res, tmp, data->nodeSetOp);
345
2.09k
        if(tmp2 == NULL) {
346
0
            xmlSecInternalError2("xmlSecNodeSetAdd", NULL,
347
0
                "nodeSetOp=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(data->nodeSetOp));
348
0
            if((res != NULL) && (res != nodes)) {
349
0
                xmlSecNodeSetDestroy(res);
350
0
            }
351
0
            xmlSecNodeSetDestroy(tmp);
352
0
            return(NULL);
353
0
        }
354
2.09k
        res = tmp2;
355
2.09k
    }
356
357
2.09k
    return(res);
358
6.48k
}
359
360
/******************************************************************************
361
 *
362
 * XPath/XPointer transforms
363
 *
364
 * xmlSecTransform + xmlSecXPathDataList
365
 *
366
  *****************************************************************************/
367
77.8k
XMLSEC_TRANSFORM_DECLARE(XPath, xmlSecPtrList)
368
77.8k
#define xmlSecXPathSize XMLSEC_TRANSFORM_SIZE(XPath)
369
77.8k
370
77.8k
#define xmlSecTransformXPathCheckId(transform) \
371
77.8k
    (xmlSecTransformCheckId((transform), xmlSecTransformXPathId) || \
372
77.8k
     xmlSecTransformCheckId((transform), xmlSecTransformXPath2Id) || \
373
77.8k
     xmlSecTransformCheckId((transform), xmlSecTransformXPointerId))
374
77.8k
375
77.8k
static int              xmlSecTransformXPathInitialize  (xmlSecTransformPtr transform);
376
77.8k
static void             xmlSecTransformXPathFinalize    (xmlSecTransformPtr transform);
377
77.8k
static int              xmlSecTransformXPathExecute     (xmlSecTransformPtr transform,
378
77.8k
                                                         int last,
379
77.8k
                                                         xmlSecTransformCtxPtr transformCtx);
380
77.8k
381
77.8k
static int
382
77.8k
xmlSecTransformXPathInitialize(xmlSecTransformPtr transform) {
383
6.48k
    xmlSecPtrListPtr dataList;
384
6.48k
    int ret;
385
386
6.48k
    xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
387
388
6.48k
    dataList = xmlSecXPathGetCtx(transform);
389
6.48k
    xmlSecAssert2(dataList != NULL, -1);
390
391
6.48k
    ret = xmlSecPtrListInitialize(dataList, xmlSecXPathDataListId);
392
6.48k
    if(ret < 0) {
393
0
        xmlSecInternalError("xmlSecPtrListInitialize",
394
0
                            xmlSecTransformGetName(transform));
395
0
        return(-1);
396
0
    }
397
6.48k
    return(0);
398
6.48k
}
399
400
static void
401
6.48k
xmlSecTransformXPathFinalize(xmlSecTransformPtr transform) {
402
6.48k
    xmlSecPtrListPtr dataList;
403
404
6.48k
    xmlSecAssert(xmlSecTransformXPathCheckId(transform));
405
406
6.48k
    dataList = xmlSecXPathGetCtx(transform);
407
6.48k
    xmlSecAssert(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId));
408
409
6.48k
    xmlSecPtrListFinalize(dataList);
410
6.48k
}
411
412
static int
413
xmlSecTransformXPathExecute(xmlSecTransformPtr transform, int last,
414
6.48k
                            xmlSecTransformCtxPtr transformCtx) {
415
6.48k
    xmlSecPtrListPtr dataList;
416
6.48k
    xmlDocPtr doc;
417
418
6.48k
    xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
419
6.48k
    xmlSecAssert2(transform->hereNode != NULL, -1);
420
6.48k
    xmlSecAssert2(transform->outNodes == NULL, -1);
421
6.48k
    xmlSecAssert2(last != 0, -1);
422
6.48k
    xmlSecAssert2(transformCtx != NULL, -1);
423
424
6.48k
    dataList = xmlSecXPathGetCtx(transform);
425
6.48k
    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
426
6.48k
    xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, -1);
427
428
6.48k
    doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
429
6.48k
    xmlSecAssert2(doc != NULL, -1);
430
431
6.48k
    transform->outNodes = xmlSecXPathDataListExecute(dataList, doc,
432
6.48k
                                transform->hereNode, transform->inNodes);
433
6.48k
    if(transform->outNodes == NULL) {
434
4.38k
        xmlSecInternalError("xmlSecXPathDataListExecute",
435
4.38k
                            xmlSecTransformGetName(transform));
436
4.38k
        return(-1);
437
4.38k
    }
438
2.09k
    return(0);
439
6.48k
}
440
441
/******************************************************************************
442
 *
443
 * XPath transform
444
 *
445
  *****************************************************************************/
446
static int              xmlSecTransformXPathNodeRead    (xmlSecTransformPtr transform,
447
                                                         xmlNodePtr node,
448
                                                         xmlSecTransformCtxPtr transformCtx);
449
450
static xmlSecTransformKlass xmlSecTransformXPathKlass = {
451
    /* klass/object sizes */
452
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
453
    xmlSecXPathSize,                            /* xmlSecSize objSize */
454
455
    xmlSecNameXPath,                            /* const xmlChar* name; */
456
    xmlSecXPathNs,                              /* const xmlChar* href; */
457
    xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
458
459
    xmlSecTransformXPathInitialize,             /* xmlSecTransformInitializeMethod initialize; */
460
    xmlSecTransformXPathFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
461
    xmlSecTransformXPathNodeRead,               /* xmlSecTransformNodeReadMethod readNode; */
462
    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
463
    NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
464
    NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
465
    NULL,                                       /* xmlSecTransformValidateMethod validate; */
466
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
467
    NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
468
    NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
469
    xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
470
    xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
471
    xmlSecTransformXPathExecute,                /* xmlSecTransformExecuteMethod execute; */
472
473
    NULL,                                       /* void* reserved0; */
474
    NULL,                                       /* void* reserved1; */
475
};
476
477
/**
478
 * @brief Gets the XPath transform klass.
479
 * @details The XPath transform evaluates given XPath expression and
480
 * intersects the result with the previous nodes set. See
481
 * http://www.w3.org/TR/xmldsig-core/#sec-XPath for more details.
482
 * @return XPath transform id.
483
 */
484
xmlSecTransformId
485
19.4k
xmlSecTransformXPathGetKlass(void) {
486
19.4k
    return(&xmlSecTransformXPathKlass);
487
19.4k
}
488
489
0
#define XMLSEC_TRANSFORM_XPATH_TMPL "(//. | //@* | //namespace::*)[boolean(%s)]"
490
491
static int
492
0
xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
493
0
    xmlSecPtrListPtr dataList;
494
0
    xmlSecXPathDataPtr data;
495
0
    xmlNodePtr cur;
496
0
    xmlChar* tmp;
497
0
    xmlSecSize tmpSize;
498
0
    int tmpLen;
499
0
    int ret;
500
501
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPathId), -1);
502
0
    xmlSecAssert2(node != NULL, -1);
503
0
    xmlSecAssert2(transformCtx != NULL, -1);
504
505
0
    dataList = xmlSecXPathGetCtx(transform);
506
0
    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
507
0
    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
508
509
    /* there is only one required node */
510
0
    cur = xmlSecGetNextElementNode(node->children);
511
0
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPath, xmlSecDSigNs))) {
512
0
        xmlSecInvalidNodeError(cur, xmlSecNodeXPath,
513
0
                               xmlSecTransformGetName(transform));
514
0
        return(-1);
515
0
    }
516
517
    /* read information from the node */
518
0
    data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath);
519
0
    if(data == NULL) {
520
0
        xmlSecInternalError("xmlSecXPathDataCreate",
521
0
                            xmlSecTransformGetName(transform));
522
0
        return(-1);
523
0
    }
524
525
0
    ret = xmlSecXPathDataNodeRead(data, cur);
526
0
    if(ret < 0) {
527
0
        xmlSecInternalError("xmlSecXPathDataNodeRead",
528
0
                            xmlSecTransformGetName(transform));
529
0
        xmlSecXPathDataDestroy(data);
530
0
        return(-1);
531
0
    }
532
533
    /* append it to the list */
534
0
    ret = xmlSecPtrListAdd(dataList, data);
535
0
    if(ret < 0) {
536
0
        xmlSecInternalError("xmlSecPtrListAdd",
537
0
                            xmlSecTransformGetName(transform));
538
0
        xmlSecXPathDataDestroy(data);
539
0
        return(-1);
540
0
    }
541
542
    /* create full XPath expression */
543
0
    xmlSecAssert2(data->expr != NULL, -1);
544
0
    tmpLen = xmlStrlen(data->expr) + xmlStrlen(BAD_CAST XMLSEC_TRANSFORM_XPATH_TMPL) + 1;
545
0
    XMLSEC_SAFE_CAST_INT_TO_SIZE(tmpLen, tmpSize, return(-1), NULL);
546
547
0
    tmp = (xmlChar*) xmlMalloc(sizeof(xmlChar) * tmpSize);
548
0
    if(tmp == NULL) {
549
0
        xmlSecMallocError(sizeof(xmlChar) * tmpSize,
550
0
                          xmlSecTransformGetName(transform));
551
0
        return(-1);
552
0
    }
553
0
    ret = xmlStrPrintf(tmp, tmpLen, XMLSEC_TRANSFORM_XPATH_TMPL, (char*)data->expr);
554
0
    if(ret < 0) {
555
0
       xmlSecXmlError("xmlStrPrintf", xmlSecTransformGetName(transform));
556
0
       xmlFree(tmp);
557
0
       return(-1);
558
0
    }
559
0
    xmlFree(data->expr);
560
0
    data->expr = tmp;
561
562
    /* set correct node set type and operation */
563
0
    data->nodeSetOp     = xmlSecNodeSetIntersection;
564
0
    data->nodeSetType   = xmlSecNodeSetNormal;
565
566
    /* check that we have nothing else */
567
0
    cur = xmlSecGetNextElementNode(cur->next);
568
0
    if(cur != NULL) {
569
0
        xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform));
570
0
        return(-1);
571
0
    }
572
0
    return(0);
573
0
}
574
575
/******************************************************************************
576
 *
577
 * XPath2 transform
578
 *
579
  *****************************************************************************/
580
static int              xmlSecTransformXPath2NodeRead   (xmlSecTransformPtr transform,
581
                                                         xmlNodePtr node,
582
                                                         xmlSecTransformCtxPtr transformCtx);
583
static xmlSecTransformKlass xmlSecTransformXPath2Klass = {
584
    /* klass/object sizes */
585
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
586
    xmlSecXPathSize,                            /* xmlSecSize objSize */
587
588
    xmlSecNameXPath2,                           /* const xmlChar* name; */
589
    xmlSecXPath2Ns,                             /* const xmlChar* href; */
590
    xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
591
592
    xmlSecTransformXPathInitialize,             /* xmlSecTransformInitializeMethod initialize; */
593
    xmlSecTransformXPathFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
594
    xmlSecTransformXPath2NodeRead,              /* xmlSecTransformNodeReadMethod readNode; */
595
    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
596
    NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
597
    NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
598
    NULL,                                       /* xmlSecTransformValidateMethod validate; */
599
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
600
    NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
601
    NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
602
    xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
603
    xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
604
    xmlSecTransformXPathExecute,                /* xmlSecTransformExecuteMethod execute; */
605
606
    NULL,                                       /* void* reserved0; */
607
    NULL,                                       /* void* reserved1; */
608
};
609
610
/**
611
 * @brief Gets the XPath2 transform klass.
612
 * @details The XPath2 transform (http://www.w3.org/TR/xmldsig-filter2/).
613
 * @return XPath2 transform klass.
614
 */
615
xmlSecTransformId
616
19.4k
xmlSecTransformXPath2GetKlass(void) {
617
19.4k
    return(&xmlSecTransformXPath2Klass);
618
19.4k
}
619
620
static int
621
0
xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
622
0
    xmlSecPtrListPtr dataList;
623
0
    xmlSecXPathDataPtr data;
624
0
    xmlNodePtr cur;
625
0
    xmlChar* op;
626
0
    int ret;
627
628
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPath2Id), -1);
629
0
    xmlSecAssert2(node != NULL, -1);
630
0
    xmlSecAssert2(transformCtx != NULL, -1);
631
632
0
    dataList = xmlSecXPathGetCtx(transform);
633
0
    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
634
0
    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
635
636
    /* There are only xpath nodes */
637
0
    cur = xmlSecGetNextElementNode(node->children);
638
0
    while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeXPath2, xmlSecXPath2Ns)) {
639
        /* read information from the node */
640
0
        data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath2);
641
0
        if(data == NULL) {
642
0
            xmlSecInternalError("xmlSecXPathDataCreate",
643
0
                                xmlSecTransformGetName(transform));
644
0
            return(-1);
645
0
        }
646
647
0
        ret = xmlSecXPathDataNodeRead(data, cur);
648
0
        if(ret < 0) {
649
0
            xmlSecInternalError("xmlSecXPathDataNodeRead",
650
0
                                xmlSecTransformGetName(transform));
651
0
            xmlSecXPathDataDestroy(data);
652
0
            return(-1);
653
0
        }
654
655
        /* append it to the list */
656
0
        ret = xmlSecPtrListAdd(dataList, data);
657
0
        if(ret < 0) {
658
0
            xmlSecInternalError("xmlSecPtrListAdd",
659
0
                                xmlSecTransformGetName(transform));
660
0
            xmlSecXPathDataDestroy(data);
661
0
            return(-1);
662
0
        }
663
664
        /* set correct node set type and operation */
665
0
        data->nodeSetType = xmlSecNodeSetTree;
666
0
        op = xmlGetProp(cur, xmlSecAttrFilter);
667
0
        if(op == NULL) {
668
0
            xmlSecInvalidNodeAttributeError(cur, xmlSecAttrFilter,
669
0
                                            xmlSecTransformGetName(transform),
670
0
                                            "empty");
671
0
            return(-1);
672
0
        }
673
0
        if(xmlStrEqual(op, xmlSecXPath2FilterIntersect)) {
674
0
            data->nodeSetOp = xmlSecNodeSetIntersection;
675
0
        } else if(xmlStrEqual(op, xmlSecXPath2FilterSubtract)) {
676
0
            data->nodeSetOp = xmlSecNodeSetSubtraction;
677
0
        } else if(xmlStrEqual(op, xmlSecXPath2FilterUnion)) {
678
0
            data->nodeSetOp = xmlSecNodeSetUnion;
679
0
        } else {
680
0
            xmlSecInvalidNodeAttributeError(cur, xmlSecAttrFilter,
681
0
                                            xmlSecTransformGetName(transform),
682
0
                                            "unknown");
683
0
            xmlFree(op);
684
0
            return(-1);
685
0
        }
686
0
        xmlFree(op);
687
688
0
        cur = xmlSecGetNextElementNode(cur->next);
689
0
    }
690
691
    /* check that we have at least one XPath node */
692
0
    if(xmlSecPtrListGetSize(dataList) == 0) {
693
0
        xmlSecInvalidNodeContentError(node, xmlSecTransformGetName(transform), "empty");
694
0
        return(-1);
695
0
    }
696
697
    /* check that we have nothing else */
698
0
    if(cur != NULL) {
699
0
        xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform));
700
0
        return(-1);
701
0
    }
702
0
    return(0);
703
0
}
704
705
/******************************************************************************
706
 *
707
 * XPointer transform
708
 *
709
  *****************************************************************************/
710
static int              xmlSecTransformXPointerNodeRead (xmlSecTransformPtr transform,
711
                                                         xmlNodePtr node,
712
                                                         xmlSecTransformCtxPtr transformCtx);
713
static xmlSecTransformKlass xmlSecTransformXPointerKlass = {
714
    /* klass/object sizes */
715
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
716
    xmlSecXPathSize,                            /* xmlSecSize objSize */
717
718
    xmlSecNameXPointer,                         /* const xmlChar* name; */
719
    xmlSecXPointerNs,                           /* const xmlChar* href; */
720
    xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
721
722
    xmlSecTransformXPathInitialize,             /* xmlSecTransformInitializeMethod initialize; */
723
    xmlSecTransformXPathFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
724
    xmlSecTransformXPointerNodeRead,            /* xmlSecTransformNodeReadMethod readNode; */
725
    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
726
    NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
727
    NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
728
    NULL,                                       /* xmlSecTransformValidateMethod validate; */
729
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
730
    NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
731
    NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
732
    xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
733
    xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
734
    xmlSecTransformXPathExecute,                /* xmlSecTransformExecuteMethod execute; */
735
736
    NULL,                                       /* void* reserved0; */
737
    NULL,                                       /* void* reserved1; */
738
};
739
740
/**
741
 * @brief Gets the XPointer transform klass.
742
 * @details The XPointer transform klass
743
 * (https://www.rfc-editor.org/rfc/rfc9231.html).
744
 * @return XPointer transform klass.
745
 */
746
xmlSecTransformId
747
32.4k
xmlSecTransformXPointerGetKlass(void) {
748
32.4k
    return(&xmlSecTransformXPointerKlass);
749
32.4k
}
750
751
/**
752
 * @brief Sets the XPointer expression for a transform.
753
 * @details Sets the XPointer expression for an XPointer @p transform.
754
 * @param transform the pointer to XPointer transform.
755
 * @param expr the XPointer expression.
756
 * @param nodeSetType the type of evaluated XPointer expression.
757
 * @param hereNode the pointer to "here" node.
758
 * @return 0 on success or a negative value if an error occurs.
759
 */
760
int
761
xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform, const xmlChar* expr,
762
6.48k
                            xmlSecNodeSetType  nodeSetType, xmlNodePtr hereNode) {
763
6.48k
    xmlSecPtrListPtr dataList;
764
6.48k
    xmlSecXPathDataPtr data;
765
6.48k
    int ret;
766
767
6.48k
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
768
6.48k
    xmlSecAssert2(transform->hereNode == NULL, -1);
769
6.48k
    xmlSecAssert2(expr != NULL, -1);
770
6.48k
    xmlSecAssert2(hereNode != NULL, -1);
771
772
6.48k
    dataList = xmlSecXPathGetCtx(transform);
773
6.48k
    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
774
6.48k
    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
775
776
6.48k
    data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
777
6.48k
    if(data == NULL) {
778
0
        xmlSecInternalError("xmlSecXPathDataCreate",
779
0
                            xmlSecTransformGetName(transform));
780
0
        return(-1);
781
0
    }
782
783
6.48k
    ret = xmlSecXPathDataRegisterNamespaces(data, hereNode);
784
6.48k
    if(ret < 0) {
785
0
        xmlSecInternalError("xmlSecXPathDataRegisterNamespaces",
786
0
                            xmlSecTransformGetName(transform));
787
0
        xmlSecXPathDataDestroy(data);
788
0
        return(-1);
789
0
    }
790
791
6.48k
    ret = xmlSecXPathDataSetExpr(data, expr);
792
6.48k
    if(ret < 0) {
793
0
        xmlSecInternalError("xmlSecXPathDataSetExpr",
794
0
                            xmlSecTransformGetName(transform));
795
0
        xmlSecXPathDataDestroy(data);
796
0
        return(-1);
797
0
    }
798
799
    /* append it to the list */
800
6.48k
    ret = xmlSecPtrListAdd(dataList, data);
801
6.48k
    if(ret < 0) {
802
0
        xmlSecInternalError("xmlSecPtrListAdd",
803
0
                            xmlSecTransformGetName(transform));
804
0
        xmlSecXPathDataDestroy(data);
805
0
        return(-1);
806
0
    }
807
808
    /* set correct node set type and operation */
809
6.48k
    data->nodeSetOp     = xmlSecNodeSetIntersection;
810
6.48k
    data->nodeSetType   = nodeSetType;
811
812
    /* set the "here" node only after all fallible operations succeeded,
813
     * so a failed call leaves the transform unmodified */
814
6.48k
    transform->hereNode = hereNode;
815
816
6.48k
    return(0);
817
6.48k
}
818
819
static int
820
0
xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
821
0
    xmlSecPtrListPtr dataList;
822
0
    xmlSecXPathDataPtr data;
823
0
    xmlNodePtr cur;
824
0
    int ret;
825
826
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
827
0
    xmlSecAssert2(node != NULL, -1);
828
0
    xmlSecAssert2(transformCtx != NULL, -1);
829
830
0
    dataList = xmlSecXPathGetCtx(transform);
831
0
    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
832
0
    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
833
834
    /* there is only one required node */
835
0
    cur = xmlSecGetNextElementNode(node->children);
836
0
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPointer, xmlSecXPointerNs))) {
837
0
        xmlSecInvalidNodeError(cur, xmlSecNodeXPointer,
838
0
                               xmlSecTransformGetName(transform));
839
0
        return(-1);
840
0
    }
841
842
    /* read information from the node */
843
0
    data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
844
0
    if(data == NULL) {
845
0
        xmlSecInternalError("xmlSecXPathDataCreate",
846
0
                            xmlSecTransformGetName(transform));
847
0
        return(-1);
848
0
    }
849
850
0
    ret = xmlSecXPathDataNodeRead(data, cur);
851
0
    if(ret < 0) {
852
0
        xmlSecInternalError("xmlSecXPathDataNodeRead",
853
0
                            xmlSecTransformGetName(transform));
854
0
        xmlSecXPathDataDestroy(data);
855
0
        return(-1);
856
0
    }
857
858
    /* append it to the list */
859
0
    ret = xmlSecPtrListAdd(dataList, data);
860
0
    if(ret < 0) {
861
0
        xmlSecInternalError("xmlSecPtrListAdd",
862
0
                            xmlSecTransformGetName(transform));
863
0
        xmlSecXPathDataDestroy(data);
864
0
        return(-1);
865
0
    }
866
867
    /* set correct node set type and operation */
868
0
    data->nodeSetOp     = xmlSecNodeSetIntersection;
869
0
    data->nodeSetType   = xmlSecNodeSetTree;
870
871
    /* check that we have nothing else */
872
0
    cur = xmlSecGetNextElementNode(cur->next);
873
0
    if(cur != NULL) {
874
0
        xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform));
875
0
        return(-1);
876
0
    }
877
0
    return(0);
878
0
}
879
880
881
/******************************************************************************
882
 *
883
 * Visa3DHack transform
884
 *
885
 * xmlSecTransform + xmlChar* (pointer to ID)
886
 *
887
  *****************************************************************************/
888
0
XMLSEC_TRANSFORM_DECLARE(Visa3DHack, xmlChar*)
889
0
#define xmlSecVisa3DHackSize XMLSEC_TRANSFORM_SIZE(Visa3DHack)
890
0
891
0
#define xmlSecTransformVisa3DHackCheckId(transform) \
892
0
    (xmlSecTransformCheckId((transform), xmlSecTransformVisa3DHackId))
893
0
894
0
static int              xmlSecTransformVisa3DHackInitialize     (xmlSecTransformPtr transform);
895
0
static void             xmlSecTransformVisa3DHackFinalize       (xmlSecTransformPtr transform);
896
0
static int              xmlSecTransformVisa3DHackExecute        (xmlSecTransformPtr transform,
897
0
                                                                 int last,
898
0
                                                                 xmlSecTransformCtxPtr transformCtx);
899
0
900
0
static xmlSecTransformKlass xmlSecTransformVisa3DHackKlass = {
901
0
    /* klass/object sizes */
902
0
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
903
0
    xmlSecVisa3DHackSize,                       /* xmlSecSize objSize */
904
0
905
0
    BAD_CAST "Visa3DHackTransform",             /* const xmlChar* name; */
906
0
    NULL,                                       /* const xmlChar* href; */
907
0
    xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
908
0
909
0
    xmlSecTransformVisa3DHackInitialize,        /* xmlSecTransformInitializeMethod initialize; */
910
0
    xmlSecTransformVisa3DHackFinalize,          /* xmlSecTransformFinalizeMethod finalize; */
911
0
    NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
912
0
    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
913
0
    NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
914
0
    NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
915
0
    NULL,                                       /* xmlSecTransformValidateMethod validate; */
916
0
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
917
0
    NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
918
0
    NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
919
0
    xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
920
0
    xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
921
0
    xmlSecTransformVisa3DHackExecute,           /* xmlSecTransformExecuteMethod execute; */
922
0
923
0
    NULL,                                       /* void* reserved0; */
924
0
    NULL,                                       /* void* reserved1; */
925
0
};
926
0
927
0
/**
928
0
 * @brief Gets the Visa3DHack transform klass.
929
0
 * @details The Visa3DHack transform klass. The only reason why we need this
930
0
 * is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows
931
0
 * invalid XPointer expressions in the URI attribute. Since we couldn't evaluate
932
0
 * such expressions thru XPath/XPointer engine, we need to have this hack here.
933
0
 * @return Visa3DHack transform klass.
934
0
 */
935
0
xmlSecTransformId
936
0
xmlSecTransformVisa3DHackGetKlass(void) {
937
0
    return(&xmlSecTransformVisa3DHackKlass);
938
0
}
939
940
/**
941
 * @brief Sets the ID value for an Visa3DHack @p transform.
942
 * @param transform the pointer to Visa3DHack transform.
943
 * @param id the ID value.
944
 * @return 0 on success or a negative value if an error occurs.
945
 */
946
int
947
0
xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform, const xmlChar* id) {
948
0
    xmlChar** idPtr;
949
950
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformVisa3DHackId), -1);
951
0
    xmlSecAssert2(id != NULL, -1);
952
953
0
    idPtr = xmlSecVisa3DHackGetCtx(transform);
954
0
    xmlSecAssert2(idPtr != NULL, -1);
955
0
    xmlSecAssert2((*idPtr) == NULL, -1);
956
957
0
    (*idPtr) = xmlStrdup(id);
958
0
    if((*idPtr) == NULL) {
959
0
        xmlSecStrdupError(id, xmlSecTransformGetName(transform));
960
0
        return(-1);
961
0
    }
962
963
0
    return(0);
964
0
}
965
966
static int
967
0
xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform) {
968
0
    xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
969
970
0
    return(0);
971
0
}
972
973
static void
974
0
xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform) {
975
0
    xmlChar** idPtr;
976
977
0
    xmlSecAssert(xmlSecTransformVisa3DHackCheckId(transform));
978
979
0
    idPtr = xmlSecVisa3DHackGetCtx(transform);
980
0
    xmlSecAssert(idPtr != NULL);
981
982
0
    if((*idPtr) != NULL) {
983
0
        xmlFree((*idPtr));
984
0
    }
985
0
    (*idPtr) = NULL;
986
0
}
987
988
static int
989
xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last,
990
0
                            xmlSecTransformCtxPtr transformCtx) {
991
0
    xmlChar** idPtr;
992
0
    xmlDocPtr doc;
993
0
    xmlAttrPtr attr;
994
0
    xmlNodeSetPtr nodeSet;
995
996
0
    xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
997
0
    xmlSecAssert2(transform->outNodes == NULL, -1);
998
0
    xmlSecAssert2(last != 0, -1);
999
0
    xmlSecAssert2(transformCtx != NULL, -1);
1000
1001
0
    idPtr = xmlSecVisa3DHackGetCtx(transform);
1002
0
    xmlSecAssert2(idPtr != NULL, -1);
1003
0
    xmlSecAssert2((*idPtr) != NULL, -1);
1004
1005
    /* if there are no input nodes we must have a "here" node to get the
1006
     * document from (in the normal flow inNodes is always set) */
1007
0
    if(transform->inNodes == NULL) {
1008
0
        xmlSecAssert2(transform->hereNode != NULL, -1);
1009
0
    }
1010
1011
0
    doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
1012
0
    xmlSecAssert2(doc != NULL, -1);
1013
1014
0
    attr = xmlGetID(doc, (*idPtr));
1015
0
    if((attr == NULL) || (attr->parent == NULL)) {
1016
0
        xmlSecXmlError2("xmlGetID", xmlSecTransformGetName(transform),
1017
0
                        "id=\"%s\"", xmlSecErrorsSafeString(*idPtr));
1018
0
        return(-1);
1019
0
    }
1020
1021
0
    nodeSet = xmlXPathNodeSetCreate(attr->parent);
1022
0
    if(nodeSet == NULL) {
1023
0
        xmlSecXmlError2("xmlXPathNodeSetCreate", xmlSecTransformGetName(transform),
1024
0
                        "id=\"%s\"", xmlSecErrorsSafeString(*idPtr));
1025
0
        return(-1);
1026
0
    }
1027
1028
0
    transform->outNodes = xmlSecNodeSetCreate(doc, nodeSet, xmlSecNodeSetTreeWithoutComments);
1029
0
    if(transform->outNodes == NULL) {
1030
0
        xmlSecInternalError("xmlSecNodeSetCreate",
1031
0
                            xmlSecTransformGetName(transform));
1032
0
        xmlXPathFreeNodeSet(nodeSet);
1033
0
        return(-1);
1034
0
    }
1035
0
    return(0);
1036
0
}