varnish-cache/lib/libvmod_blob/vmod_blob.c
1
/*-
2
 * Copyright 2015-2017 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5
 * Authors: Nils Goroll <nils.goroll@uplex.de>
6
 *          Geoffrey Simmons <geoffrey.simmons@uplex.de>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions are met:
10
 * 1. Redistributions of source code must retain the above copyright notice,
11
 *    this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 *
27
 */
28
29
#include "config.h"
30
#include <errno.h>
31
#include <string.h>
32
33
#include "cache/cache.h"
34
35
#include "vcc_if.h"
36
#include "vmod_blob.h"
37
38
struct vmod_blob_blob {
39
        unsigned magic;
40
#define VMOD_BLOB_MAGIC 0xfade4fa9
41
        struct vmod_priv blob;
42
        char *encoding[__MAX_ENCODING][2];
43
        pthread_mutex_t lock;
44
};
45
46
#define B64_FUNCS                                  \
47
                .decode_l       = base64_decode_l, \
48
                .decode         = base64_decode,   \
49
                .encode         = base64_encode
50
51
static const struct vmod_blob_fptr {
52
        len_f           *const decode_l;
53
        decode_f        *const decode;
54
        len_f           *const encode_l;
55
        encode_f        *const encode;
56
} func[__MAX_ENCODING] = {
57
        [IDENTITY] = {
58
                .decode_l       = id_decode_l,
59
                .decode         = id_decode,
60
                .encode_l       = id_encode_l,
61
                .encode         = id_encode
62
        },
63
        [BASE64] = {
64
                B64_FUNCS,
65
                .encode_l       = base64_encode_l
66
        },
67
        [BASE64URL] = {
68
                B64_FUNCS,
69
                .encode_l       = base64_encode_l
70
        },
71
        [BASE64URLNOPAD] = {
72
                B64_FUNCS,
73
                .encode_l       = base64nopad_encode_l
74
        },
75
        [HEX] = {
76
                .decode_l       = hex_decode_l,
77
                .decode         = hex_decode,
78
                .encode_l       = hex_encode_l,
79
                .encode         = hex_encode
80
        },
81
        [URL] = {
82
                .decode_l       = url_decode_l,
83
                .decode         = url_decode,
84
                .encode_l       = url_encode_l,
85
                .encode         = url_encode
86
        },
87
};
88
89
#undef B64_FUNCS
90
91
#define ERR(ctx, msg) \
92
        VRT_fail((ctx), "vmod blob error: " msg)
93
94
#define VERR(ctx, fmt, ...) \
95
        VRT_fail((ctx), "vmod blob error: " fmt, __VA_ARGS__)
96
97
#define ERRINVAL(ctx, enc) \
98
        VERR((ctx), "cannot decode, illegal encoding beginning with \"%s\"", \
99
             (enc))
100
101
#define VERRNOMEM(ctx, fmt, ...) \
102
        VERR((ctx), fmt ", out of space", __VA_ARGS__)
103
104
#define ERRNOMEM(ctx, msg) \
105
        ERR((ctx), msg ", out of space")
106
107
static char empty[1] = { '\0' };
108
109
static const struct vmod_priv null_blob[1] =
110
{
111
        {
112
                .priv = empty,
113
                .len = 0,
114
                .free = NULL
115
        }
116
};
117
118
static enum encoding
119 4560
parse_encoding(VCL_ENUM e)
120
{
121
#define VMODENUM(n) if (e == vmod_enum_ ## n) return(n);
122
#include "tbl_encodings.h"
123 0
        WRONG("illegal encoding enum");
124
}
125
126
static enum case_e
127 2632
parse_case(VCL_ENUM e)
128
{
129
#define VMODENUM(n) if (e == vmod_enum_ ## n) return(n);
130
#include "tbl_case.h"
131 0
        WRONG("illegal case enum");
132
}
133
134
135
static inline size_t
136 920
decode_l(enum encoding dec, VCL_STRANDS s)
137
{
138 920
        size_t len = 0;
139
140 920
        AENC(dec);
141
142 2024
        for (int i = 0; i < s->n; i++)
143 1104
                if (s->p[i] != NULL && *s->p[i] != '\0')
144 984
                        len += strlen(s->p[i]);
145
146 920
        return(func[dec].decode_l(len));
147
}
148
149
static void
150 152
err_decode(VRT_CTX, const char *enc)
151
{
152 152
        switch (errno) {
153
        case EINVAL:
154 136
                ERRINVAL(ctx, enc);
155 136
                break;
156
        case ENOMEM:
157 16
                ERRNOMEM(ctx, "cannot decode");
158 16
                break;
159
        default:
160 0
                WRONG("invalid errno");
161
        }
162 152
}
163
164
static inline int
165 2736
encodes_hex(enum encoding enc)
166
{
167 2736
        return (enc == HEX || enc == URL);
168
}
169
170
/* Require case DEFAULT for all encodings besides HEX and URL. */
171
172
static inline int
173 2632
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc,
174
               enum case_e kase)
175
{
176 2632
        if (!encodes_hex(enc) && kase != DEFAULT) {
177 64
                VERR(ctx, "case %s is illegal with encoding %s", case_s, encs);
178 64
                return 0;
179
        }
180 2568
        return 1;
181
}
182
183
/* Objects */
184
185
VCL_VOID v_matchproto_(td_blob_blob__init)
186 200
vmod_blob__init(VRT_CTX, struct vmod_blob_blob **blobp, const char *vcl_name,
187
                VCL_ENUM decs, VCL_STRANDS strings)
188
{
189
        struct vmod_blob_blob *b;
190 200
        enum encoding dec = parse_encoding(decs);
191
        ssize_t len;
192
193 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
194 200
        AN(blobp);
195 200
        AZ(*blobp);
196 200
        AN(vcl_name);
197 200
        AENC(dec);
198 200
        AN(strings);
199
200 200
        ALLOC_OBJ(b, VMOD_BLOB_MAGIC);
201 200
        AN(b);
202 200
        *blobp = b;
203 200
        b->blob.free = NULL;
204 200
        AZ(pthread_mutex_init(&b->lock, NULL));
205
206 200
        len = decode_l(dec, strings);
207 200
        if (len == 0) {
208 32
                b->blob.len = 0;
209 32
                b->blob.priv = NULL;
210 32
                return;
211
        }
212 168
        assert(len > 0);
213
214 168
        b->blob.priv = malloc(len);
215 168
        if (b->blob.priv == NULL) {
216 0
                VERRNOMEM(ctx, "cannot create blob %s", vcl_name);
217 0
                return;
218
        }
219
220 168
        errno = 0;
221 168
        len = func[dec].decode(dec, b->blob.priv, len, -1, strings);
222
223 168
        if (len == -1) {
224 32
                assert(errno == EINVAL);
225 32
                free(b->blob.priv);
226 32
                b->blob.priv = NULL;
227 32
                VERR(ctx, "cannot create blob %s, illegal encoding beginning "
228
                    "with \"%s\"", vcl_name, strings->p[0]);
229 32
                return;
230
        }
231 136
        if (len == 0) {
232 0
                b->blob.len = 0;
233 0
                free(b->blob.priv);
234 0
                b->blob.priv = NULL;
235 0
                return;
236
        }
237 136
        b->blob.len = len;
238
}
239
240
VCL_BLOB v_matchproto_(td_blob_blob_get)
241 428
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b)
242
{
243 428
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
244 428
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
245 428
        return &b->blob;
246
}
247
248
VCL_STRING v_matchproto_(td_blob_blob_encode)
249 708
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs,
250
                 VCL_ENUM case_s)
251
{
252 708
        enum encoding enc = parse_encoding(encs);
253 708
        AENC(enc);
254 708
        enum case_e kase = parse_case(case_s);
255
256 708
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
257 708
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
258
259 708
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
260 32
                return NULL;
261 676
        if (b->blob.len == 0)
262 80
                return "";
263 596
        if (kase == DEFAULT)
264 364
                kase = LOWER;
265
266 596
        if (b->encoding[enc][kase] == NULL) {
267 244
                AZ(pthread_mutex_lock(&b->lock));
268 244
                if (b->encoding[enc][kase] == NULL) {
269 244
                        ssize_t len = func[enc].encode_l(b->blob.len);
270
271 244
                        assert(len >= 0);
272 244
                        if (len == 0)
273 0
                                b->encoding[enc][kase] = empty;
274
                        else {
275 244
                                b->encoding[enc][kase] = malloc(len);
276 244
                                if (b->encoding[enc][kase] == NULL)
277 0
                                        ERRNOMEM(ctx, "cannot encode");
278
                                else {
279 244
                                        char *s = b->encoding[enc][kase];
280 244
                                        len =
281 732
                                                func[enc].encode(
282
                                                        enc, kase, s, len,
283 244
                                                        b->blob.priv,
284 244
                                                        b->blob.len);
285 244
                                        assert(len >= 0);
286 244
                                        if (len == 0) {
287 0
                                                free(s);
288 0
                                                b->encoding[enc][kase] = empty;
289
                                        }
290
                                        else
291 244
                                                s[len] = '\0';
292
                                }
293
                        }
294
                }
295 244
                AZ(pthread_mutex_unlock(&b->lock));
296
        }
297 596
        return b->encoding[enc][kase];
298
}
299
300
VCL_VOID v_matchproto_(td_blob_blob__fini)
301 112
vmod_blob__fini(struct vmod_blob_blob **blobp)
302
{
303
        struct vmod_blob_blob *b;
304
305 112
        if (blobp == NULL || *blobp == NULL)
306 12
                return;
307
308 100
        b = *blobp;
309 100
        *blobp = NULL;
310 100
        CHECK_OBJ(b, VMOD_BLOB_MAGIC);
311 100
        if (b->blob.priv != NULL) {
312 56
                free(b->blob.priv);
313 56
                b->blob.priv = NULL;
314
        }
315 800
        for (int i = 0; i < __MAX_ENCODING; i++)
316 2100
                for (int j = 0; j < 2; j++) {
317 1400
                        char *s = b->encoding[i][j];
318 1400
                        if (s != NULL && s != empty) {
319 80
                                free(s);
320 80
                                b->encoding[i][j] = NULL;
321
                        }
322
                }
323 100
        AZ(pthread_mutex_destroy(&b->lock));
324 100
        FREE_OBJ(b);
325
}
326
327
/* Functions */
328
329
VCL_BLOB v_matchproto_(td_blob_decode)
330 1008
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, VCL_STRANDS strings)
331
{
332 1008
        enum encoding dec = parse_encoding(decs);
333
        struct vmod_priv *b;
334
        char *buf;
335
        uintptr_t snap;
336
        ssize_t len;
337
        unsigned space;
338
339 1008
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
340 1008
        AENC(dec);
341 1008
        AN(strings);
342 1008
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
343
344 1008
        snap = WS_Snapshot(ctx->ws);
345 1008
        if ((b = WS_Alloc(ctx->ws, sizeof(struct vmod_priv))) == NULL) {
346 4
                ERRNOMEM(ctx, "cannot decode");
347 4
                return NULL;
348
        }
349
350 1004
        buf = WS_Front(ctx->ws);
351 1004
        space = WS_Reserve(ctx->ws, 0);
352
353 1004
        if (length <= 0)
354 680
                length = -1;
355 1004
        errno = 0;
356 1004
        len = func[dec].decode(dec, buf, space, length, strings);
357
358 1004
        if (len == -1) {
359 72
                err_decode(ctx, strings->p[0]);
360 72
                WS_Release(ctx->ws, 0);
361 72
                WS_Reset(ctx->ws, snap);
362 72
                return NULL;
363
        }
364 932
        if (len == 0) {
365 168
                WS_Release(ctx->ws, 0);
366 168
                WS_Reset(ctx->ws, snap);
367 168
                return null_blob;
368
        }
369 764
        WS_Release(ctx->ws, len);
370 764
        b->priv = buf;
371 764
        b->len = len;
372 764
        b->free = NULL;
373 764
        return (b);
374
}
375
376
static VCL_STRING
377 1796
encode(VRT_CTX, enum encoding enc, enum case_e kase, VCL_BLOB b)
378
{
379
        ssize_t len;
380
        char *buf;
381
        uintptr_t snap;
382
        unsigned space;
383
384 1796
        AENC(enc);
385
386 1796
        if (b == NULL)
387 96
                return NULL;
388
389 1700
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
390 1700
        snap = WS_Snapshot(ctx->ws);
391 1700
        buf = WS_Front(ctx->ws);
392 1700
        space = WS_Reserve(ctx->ws, 0);
393
394 1700
        len = func[enc].encode(enc, kase, buf, space, b->priv, b->len);
395
396 1700
        if (len == -1) {
397 36
                ERRNOMEM(ctx, "cannot encode");
398 36
                WS_Release(ctx->ws, 0);
399 36
                WS_Reset(ctx->ws, snap);
400 36
                return NULL;
401
        }
402 1664
        if (len == 0) {
403 144
                WS_Release(ctx->ws, 0);
404 144
                WS_Reset(ctx->ws, snap);
405 144
                return "";
406
        }
407 1520
        buf[len] = '\0';
408 1520
        WS_Release(ctx->ws, len + 1);
409 1520
        return buf;
410
}
411
412
VCL_STRING v_matchproto_(td_blob_encode)
413 1204
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b)
414
{
415 1204
        enum encoding enc = parse_encoding(encs);
416 1204
        enum case_e kase = parse_case(case_s);
417
418 1204
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
419 1204
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
420 32
                return NULL;
421 1172
        return encode(ctx, enc, kase, b);
422
}
423
424
VCL_STRING v_matchproto_(td_blob_transcode)
425 720
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s,
426
               VCL_INT length, VCL_STRANDS strings)
427 720
{
428 720
        enum encoding dec = parse_encoding(decs);
429 720
        enum encoding enc = parse_encoding(encs);
430 720
        enum case_e kase = parse_case(case_s);
431
        struct vmod_priv b;
432
        VCL_STRING r;
433
434 720
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
435 720
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
436 720
        AN(strings);
437
438 720
        AENC(dec);
439 720
        AENC(enc);
440
441 720
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
442 0
                return NULL;
443
444
        /*
445
         * Allocate space for the decoded blob on the stack
446
         * ignoring the limitation imposed by n
447
         */
448 720
        size_t l = decode_l(dec, strings);
449 720
        if (l == 0)
450 0
                return "";
451
        /* XXX: handle stack overflow? */
452 720
        char buf[l];
453 720
        b.free = NULL;
454 720
        b.priv = buf;
455
456 720
        if (length <= 0)
457 380
                length = -1;
458 720
        errno = 0;
459 720
        b.len = func[dec].decode(dec, buf, l, length, strings);
460
461 720
        if (b.len == -1) {
462 80
                err_decode(ctx, strings->p[0]);
463 80
                return NULL;
464
        }
465
466
        /*
467
         * If the encoding and decoding are the same, and the decoding was
468
         * legal, just return the concatenated string.
469
         * For encodings with hex digits, we cannot assume the same result.
470
         * since the call may specify upper- or lower-case that differs
471
         * from the encoded string.
472
         */
473 640
        if (length == -1 && enc == dec && !encodes_hex(enc))
474
                /*
475
                 * Returns NULL and invokes VCL failure on workspace
476
                 * overflow. If there is only one string already in the
477
                 * workspace, then it is re-used.
478
                 */
479 16
                return (VRT_CollectStrands(ctx, strings));
480
481 624
        r = encode(ctx, enc, kase, &b);
482 624
        return (r);
483
}
484
485
VCL_BOOL v_matchproto_(td_blob_same)
486 72
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
487
{
488
        (void) ctx;
489
490 72
        if (b1 == NULL && b2 == NULL)
491 0
                return 1;
492 72
        if (b1 == NULL || b2 == NULL)
493 12
                return 0;
494 60
        return (b1->len == b2->len && b1->priv == b2->priv);
495
}
496
497
VCL_BOOL v_matchproto_(td_blob_equal)
498 48
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
499
{
500
        (void) ctx;
501
502 48
        if (b1 == NULL && b2 == NULL)
503 0
                return 1;
504 48
        if (b1 == NULL || b2 == NULL)
505 0
                return 0;
506 48
        if (b1->len != b2->len)
507 12
                return 0;
508 36
        if (b1->priv == b2->priv)
509 20
                return 1;
510 16
        if (b1->priv == NULL || b2->priv == NULL)
511 0
                return 0;
512 16
        return (memcmp(b1->priv, b2->priv, b1->len) == 0);
513
}
514
515
VCL_INT v_matchproto_(td_blob_length)
516 28
vmod_length(VRT_CTX, VCL_BLOB b)
517
{
518
        (void) ctx;
519
520 28
        if (b == NULL)
521 0
                return 0;
522 28
        return b->len;
523
}
524
525
VCL_BLOB v_matchproto_(td_blob_sub)
526 64
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off)
527
{
528
        uintptr_t snap;
529
        struct vmod_priv *sub;
530
531 64
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
532 64
        assert(n >= 0);
533 64
        assert(off >= 0);
534
535 64
        if (b == NULL || b->len == 0 || b->priv == NULL) {
536 8
                ERR(ctx, "blob is empty in blob.sub()");
537 8
                return NULL;
538
        }
539 56
        assert(b->len >= 0);
540 56
        if (off + n > b->len) {
541 16
                VERR(ctx, "size %jd from offset %jd requires more bytes than "
542
                     "blob length %d in blob.sub()",
543
                     (intmax_t)n, (intmax_t)off, b->len);
544 16
                return NULL;
545
        }
546
547 40
        if (n == 0)
548 8
                return null_blob;
549
550 32
        snap = WS_Snapshot(ctx->ws);
551 32
        if ((sub = WS_Alloc(ctx->ws, sizeof(*sub))) == NULL) {
552 4
                ERRNOMEM(ctx, "Allocating BLOB result in blob.sub()");
553 4
                return NULL;
554
        }
555 28
        if ((sub->priv = WS_Alloc(ctx->ws, n)) == NULL) {
556 4
                VERRNOMEM(ctx, "Allocating %jd bytes in blob.sub()", (intmax_t)n);
557 4
                WS_Reset(ctx->ws, snap);
558 4
                return NULL;
559
        }
560 24
        memcpy(sub->priv, (char *)b->priv + off, n);
561 24
        sub->len = n;
562 24
        return sub;
563
}