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