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