varnish-cache/vmod/vmod_blob.c
1
/*-
2
 * Copyright 2015-2017 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5 6690
 * Authors: Nils Goroll <nils.goroll@uplex.de>
6 17378
 *          Geoffrey Simmons <geoffrey.simmons@uplex.de>
7 14879
 *
8 9340
 * SPDX-License-Identifier: BSD-2-Clause
9 8640
 *
10 8620
 * Redistribution and use in source and binary forms, with or without
11 5850
 * modification, are permitted provided that the following conditions are met:
12 2500
 * 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 11549
parse_encoding(VCL_ENUM e)
119
{
120
#define VMODENUM(n)                             \
121
        do {                                    \
122
                if (e == VENUM(n)) return (n);  \
123
        } while (0);
124
#include "vmod_blob_tbl_encodings.h"
125 0
        WRONG("illegal encoding enum");
126 11550
}
127
128
static enum case_e
129 6690
parse_case(VCL_ENUM e)
130
{
131
#define VMODENUM(n)                             \
132
        do {                                    \
133
                if (e == VENUM(n)) return (n);  \
134
        } while (0);
135
#include "vmod_blob_tbl_case.h"
136 0
        WRONG("illegal case enum");
137 6690
}
138
139
140
static inline size_t
141 2320
decode_l(enum encoding dec, VCL_STRANDS s)
142
{
143 2320
        size_t len = 0;
144
145 2320
        AENC(dec);
146
147 5100
        for (int i = 0; i < s->n; i++)
148 5260
                if (s->p[i] != NULL && *s->p[i] != '\0')
149 2480
                        len += strlen(s->p[i]);
150
151 2320
        return (func[dec].decode_l(len));
152
}
153
154
static void
155 380
err_decode(VRT_CTX, const char *enc)
156
{
157 380
        switch (errno) {
158
        case EINVAL:
159 340
                ERRINVAL(ctx, enc);
160 340
                break;
161
        case ENOMEM:
162 40
                ERRNOMEM(ctx, "cannot decode");
163 40
                break;
164
        default:
165 0
                WRONG("invalid errno");
166 0
        }
167 380
}
168
169
static inline int
170 6950
encodes_hex(enum encoding enc)
171
{
172 6950
        return (enc == HEX || enc == URL);
173
}
174
175
/* Require case DEFAULT for all encodings besides HEX and URL. */
176
177
static inline int
178 6690
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc,
179
    enum case_e kase)
180
{
181 6690
        if (!encodes_hex(enc) && kase != DEFAULT) {
182 160
                VERR(ctx, "case %s is illegal with encoding %s", case_s, encs);
183 160
                return (0);
184
        }
185 6530
        return (1);
186 6690
}
187
188
/* Objects */
189
190
VCL_VOID v_matchproto_(td_blob_blob__init)
191 500
vmod_blob__init(VRT_CTX, struct vmod_blob_blob **blobp, const char *vcl_name,
192
    VCL_ENUM decs, VCL_STRANDS strings)
193
{
194
        struct vmod_blob_blob *b;
195 500
        enum encoding dec = parse_encoding(decs);
196
        void *buf;
197
        ssize_t len;
198
199 500
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
200 500
        AN(blobp);
201 500
        AZ(*blobp);
202 500
        AN(vcl_name);
203 500
        AENC(dec);
204 500
        AN(strings);
205
206 500
        ALLOC_OBJ(b, VMOD_BLOB_MAGIC);
207 500
        AN(b);
208 500
        *blobp = b;
209 500
        AZ(pthread_mutex_init(&b->lock, NULL));
210
211 500
        b->blob.type = VMOD_BLOB_TYPE;
212
213 500
        len = decode_l(dec, strings);
214 500
        if (len == 0)
215 80
                return;
216
217 420
        assert(len > 0);
218
219 420
        buf = malloc(len);
220 420
        if (buf == NULL) {
221 0
                VERRNOMEM(ctx, "cannot create blob %s", vcl_name);
222 0
                return;
223
        }
224
225 420
        errno = 0;
226 420
        len = func[dec].decode(dec, buf, len, -1, strings);
227
228 420
        if (len == -1) {
229 80
                assert(errno == EINVAL);
230 80
                free(buf);
231 80
                VERR(ctx, "cannot create blob %s, illegal encoding beginning "
232
                    "with \"%s\"", vcl_name, strings->p[0]);
233 80
                return;
234
        }
235 340
        if (len == 0) {
236 0
                free(buf);
237 0
                memcpy(&b->blob, vrt_null_blob, sizeof b->blob);
238 0
                return;
239
        }
240 340
        b->blob.len = len;
241 340
        b->blob.blob = b->freeptr = buf;
242 500
}
243
244
VCL_BLOB v_matchproto_(td_blob_blob_get)
245 1070
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b)
246
{
247 1070
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
248 1070
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
249 1070
        return (&b->blob);
250
}
251
252
VCL_STRING v_matchproto_(td_blob_blob_encode)
253 1770
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs,
254
    VCL_ENUM case_s)
255
{
256 1770
        enum encoding enc = parse_encoding(encs);
257 1770
        AENC(enc);
258 1770
        enum case_e kase = parse_case(case_s);
259
260 1770
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
261 1770
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
262
263 1770
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
264 80
                return (NULL);
265 1690
        if (b->blob.len == 0)
266 200
                return ("");
267 1490
        if (kase == DEFAULT)
268 910
                kase = LOWER;
269
270 1490
        if (b->encoding[enc][kase] == NULL) {
271 610
                AZ(pthread_mutex_lock(&b->lock));
272 610
                if (b->encoding[enc][kase] == NULL) {
273 610
                        ssize_t len = func[enc].encode_l(b->blob.len);
274
275 610
                        assert(len >= 0);
276 610
                        if (len == 0)
277 0
                                b->encoding[enc][kase] = empty;
278
                        else {
279 610
                                b->encoding[enc][kase] = malloc(len);
280 610
                                if (b->encoding[enc][kase] == NULL)
281 0
                                        ERRNOMEM(ctx, "cannot encode");
282
                                else {
283 610
                                        char *s = b->encoding[enc][kase];
284 610
                                        len =
285 1220
                                                func[enc].encode(
286 610
                                                        enc, kase, s, len,
287 610
                                                        b->blob.blob,
288 610
                                                        b->blob.len);
289 610
                                        assert(len >= 0);
290 610
                                        if (len == 0) {
291 0
                                                free(s);
292 0
                                                b->encoding[enc][kase] = empty;
293 0
                                        }
294
                                        else
295 610
                                                s[len] = '\0';
296
                                }
297
                        }
298 610
                }
299 610
                AZ(pthread_mutex_unlock(&b->lock));
300 610
        }
301 1490
        return (b->encoding[enc][kase]);
302 1770
}
303
304
VCL_VOID v_matchproto_(td_blob_blob__fini)
305 250
vmod_blob__fini(struct vmod_blob_blob **blobp)
306
{
307
        struct vmod_blob_blob *b;
308
        char *s;
309
        int i, j;
310
311 250
        TAKE_OBJ_NOTNULL(b, blobp, VMOD_BLOB_MAGIC);
312
313 250
        if (b->freeptr != NULL) {
314 140
                free(b->freeptr);
315 140
                b->blob.blob = NULL;
316 140
        }
317
318 2250
        for (i = 0; i < __MAX_ENCODING; i++)
319 6000
                for (j = 0; j < 2; j++) {
320 4000
                        s = b->encoding[i][j];
321 4000
                        if (s != NULL && s != empty) {
322 200
                                free(s);
323 200
                                b->encoding[i][j] = NULL;
324 200
                        }
325 6000
                }
326
327 250
        AZ(pthread_mutex_destroy(&b->lock));
328 250
        FREE_OBJ(b);
329 250
}
330
331
/* Functions */
332
333
VCL_BLOB v_matchproto_(td_blob_decode)
334 2540
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, VCL_STRANDS strings)
335
{
336 2540
        enum encoding dec = parse_encoding(decs);
337
        char *buf;
338
        ssize_t len;
339
        unsigned space;
340
341 2540
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
342 2540
        AENC(dec);
343 2540
        AN(strings);
344 2540
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
345
346 2540
        space = WS_ReserveAll(ctx->ws);
347 2540
        buf = WS_Reservation(ctx->ws);
348
349 2540
        if (length <= 0)
350 1730
                length = -1;
351 2540
        errno = 0;
352 2540
        len = func[dec].decode(dec, buf, space, length, strings);
353
354 2540
        if (len == -1) {
355 180
                err_decode(ctx, strings->p[0]);
356 180
                WS_Release(ctx->ws, 0);
357 180
                return (NULL);
358
        }
359 2360
        if (len == 0) {
360 420
                WS_Release(ctx->ws, 0);
361 420
                return (vrt_null_blob);
362
        }
363 1940
        WS_Release(ctx->ws, len);
364
365 1940
        assert(len > 0);
366
367 1940
        return (VRT_blob(ctx, "blob.decode", buf, len, VMOD_BLOB_TYPE));
368 2540
}
369
370
static VCL_STRING
371 4600
encode(VRT_CTX, enum encoding enc, enum case_e kase, VCL_BLOB b)
372
{
373
        ssize_t len;
374
        char *buf;
375
        unsigned space;
376
377 4600
        AENC(enc);
378
379 4600
        if (b == NULL)
380 270
                return (NULL);
381
382 4330
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
383 4330
        space = WS_ReserveAll(ctx->ws);
384 4330
        buf = WS_Reservation(ctx->ws);
385
386 4330
        len = func[enc].encode(enc, kase, buf, space, b->blob, b->len);
387
388 4330
        if (len == -1) {
389 50
                ERRNOMEM(ctx, "cannot encode");
390 50
                WS_Release(ctx->ws, 0);
391 50
                return (NULL);
392
        }
393 4280
        if (len == 0) {
394 360
                WS_Release(ctx->ws, 0);
395 360
                return ("");
396
        }
397 3920
        buf[len] = '\0';
398 3920
        WS_Release(ctx->ws, len + 1);
399 3920
        return (buf);
400 4600
}
401
402
VCL_STRING v_matchproto_(td_blob_encode)
403 3100
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b)
404
{
405 3100
        enum encoding enc = parse_encoding(encs);
406 3100
        enum case_e kase = parse_case(case_s);
407
408 3100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
409 3100
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
410 80
                return (NULL);
411 3020
        return (encode(ctx, enc, kase, b));
412 3100
}
413
414
VCL_STRING v_matchproto_(td_blob_transcode)
415 1820
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s,
416
               VCL_INT length, VCL_STRANDS strings)
417
{
418 1820
        enum encoding dec = parse_encoding(decs);
419 1820
        enum encoding enc = parse_encoding(encs);
420 1820
        enum case_e kase = parse_case(case_s);
421
        struct vrt_blob b;
422
        VCL_STRING r;
423
        size_t l;
424
        ssize_t len;
425
426 1820
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
427 1820
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
428 1820
        AN(strings);
429
430 1820
        AENC(dec);
431 1820
        AENC(enc);
432
433 1820
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
434 0
                return (NULL);
435
436
        /*
437
         * Allocate space for the decoded blob on the stack
438
         * ignoring the limitation imposed by n
439
         */
440 1820
        l = decode_l(dec, strings);
441 1820
        if (l == 0)
442 0
                return ("");
443
444
        /* XXX: handle stack overflow? */
445 1820
        char buf[l];
446
447 1820
        if (length <= 0)
448 970
                length = -1;
449 1820
        errno = 0;
450 1820
        len = func[dec].decode(dec, buf, l, length, strings);
451
452 1820
        if (len < 0) {
453 200
                err_decode(ctx, strings->p[0]);
454 200
                return (NULL);
455
        }
456
457 1620
        b.len = len;
458 1620
        b.blob = buf;
459
460
        /*
461
         * If the encoding and decoding are the same, and the decoding was
462
         * legal, just return the concatenated string.
463
         * For encodings with hex digits, we cannot assume the same result.
464
         * since the call may specify upper- or lower-case that differs
465
         * from the encoded string.
466
         */
467 1620
        if (length == -1 && enc == dec && !encodes_hex(enc))
468
                /*
469
                 * Returns NULL and invokes VCL failure on workspace
470
                 * overflow. If there is only one string already in the
471
                 * workspace, then it is re-used.
472
                 */
473 40
                return (VRT_STRANDS_string(ctx, strings));
474
475 1580
        r = encode(ctx, enc, kase, &b);
476 1580
        return (r);
477 1820
}
478
479
VCL_BOOL v_matchproto_(td_blob_same)
480 180
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
481
{
482
483 180
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
484 180
        if (b1 == b2)
485 60
                return (1);
486 120
        if (b1 == NULL || b2 == NULL)
487 30
                return (0);
488 90
        return (b1->len == b2->len && b1->blob == b2->blob);
489 180
}
490
491
VCL_BOOL v_matchproto_(td_blob_equal)
492 120
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
493
{
494
495 120
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
496 120
        if (b1 == b2)
497 30
                return (1);
498 90
        if (b1 == NULL || b2 == NULL)
499 0
                return (0);
500 90
        if (b1->len != b2->len)
501 30
                return (0);
502 60
        if (b1->blob == b2->blob)
503 20
                return (1);
504 40
        if (b1->blob == NULL || b2->blob == NULL)
505 0
                return (0);
506 40
        return (memcmp(b1->blob, b2->blob, b1->len) == 0);
507 120
}
508
509
VCL_INT v_matchproto_(td_blob_length)
510 70
vmod_length(VRT_CTX, VCL_BLOB b)
511
{
512
513 70
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
514 70
        if (b == NULL)
515 0
                return (0);
516 70
        return (b->len);
517 70
}
518
519
VCL_BLOB v_matchproto_(td_blob_sub)
520 170
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off)
521
{
522
523 170
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
524 170
        assert(n >= 0);
525 170
        assert(off >= 0);
526
527 170
        if (b == NULL || b->len == 0 || b->blob == NULL) {
528 30
                ERR(ctx, "blob is empty in blob.sub()");
529 30
                return (NULL);
530
        }
531
532 140
        assert(b->len > 0);
533
534
        // XXX check for > SIZE_MAX ?
535 140
        if (off < 0 || n < 0) {
536 0
                ERR(ctx, "size or offset negative in blob.sub()");
537 0
                return (NULL);
538
        }
539
540 140
        if ((size_t)off > b->len || (size_t)n > b->len ||
541 120
            (size_t)off + (size_t)n > b->len) {
542 40
                VERR(ctx, "size %jd from offset %jd requires more bytes than "
543
                    "blob length %zd in blob.sub()",
544
                    (intmax_t)n, (intmax_t)off, b->len);
545 40
                return (NULL);
546
        }
547
548 200
        return (VRT_blob(ctx, "blob.sub",
549 100
            (const char *)b->blob + off, n, b->type));
550 170
}