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
#include "wb.h"
38
39
struct vmod_blob_blob {
40
        unsigned magic;
41
#define VMOD_BLOB_MAGIC 0xfade4fa9
42
        struct vmod_priv blob;
43
        char *encoding[__MAX_ENCODING][2];
44
        pthread_mutex_t lock;
45
};
46
47
#define B64_FUNCS                                  \
48
                .decode_l       = base64_decode_l, \
49
                .decode         = base64_decode,   \
50
                .encode         = base64_encode
51
52
static const struct vmod_blob_fptr {
53
        len_f           *const decode_l;
54
        decode_f        *const decode;
55
        len_f           *const encode_l;
56
        encode_f        *const encode;
57
} func[__MAX_ENCODING] = {
58
        [IDENTITY] = {
59
                .decode_l       = id_decode_l,
60
                .decode         = id_decode,
61
                .encode_l       = id_encode_l,
62
                .encode         = id_encode
63
        },
64
        [BASE64] = {
65
                B64_FUNCS,
66
                .encode_l       = base64_encode_l
67
        },
68
        [BASE64URL] = {
69
                B64_FUNCS,
70
                .encode_l       = base64_encode_l
71
        },
72
        [BASE64URLNOPAD] = {
73
                B64_FUNCS,
74
                .encode_l       = base64nopad_encode_l
75
        },
76
        [HEX] = {
77
                .decode_l       = hex_decode_l,
78
                .decode         = hex_decode,
79
                .encode_l       = hex_encode_l,
80
                .encode         = hex_encode
81
        },
82
        [URL] = {
83
                .decode_l       = url_decode_l,
84
                .decode         = url_decode,
85
                .encode_l       = url_encode_l,
86
                .encode         = url_encode
87
        },
88
};
89
90
#undef B64_FUNCS
91
92
#define ERR(ctx, msg) \
93
        VRT_fail((ctx), "vmod blob error: " msg)
94
95
#define VERR(ctx, fmt, ...) \
96
        VRT_fail((ctx), "vmod blob error: " fmt, __VA_ARGS__)
97
98
#define ERRINVAL(ctx, enc) \
99
        VERR((ctx), "cannot decode, illegal encoding beginning with \"%s\"", \
100
             (enc))
101
102
#define VERRNOMEM(ctx, fmt, ...) \
103
        VERR((ctx), fmt ", out of space", __VA_ARGS__)
104
105
#define ERRNOMEM(ctx, msg) \
106
        ERR((ctx), msg ", out of space")
107
108
static char empty[1] = { '\0' };
109
110
static const struct vmod_priv null_blob[1] =
111
{
112
        {
113
                .priv = empty,
114
                .len = 0,
115
                .free = NULL
116
        }
117
};
118
119
static enum encoding
120 2174
parse_encoding(VCL_ENUM e)
121
{
122
#define VMODENUM(n) if (e == vmod_enum_ ## n) return(n);
123
#include "tbl_encodings.h"
124 0
        WRONG("illegal encoding enum");
125
}
126
127
static enum case_e
128 1256
parse_case(VCL_ENUM e)
129
{
130
#define VMODENUM(n) if (e == vmod_enum_ ## n) return(n);
131
#include "tbl_case.h"
132 0
        WRONG("illegal case enum");
133
}
134
135
136
static inline size_t
137 460
decode_l_va(enum encoding dec, const char * const p, va_list ap)
138
{
139 460
        size_t len = 0;
140
141 460
        AENC(dec);
142
143 1472
        for (const char *s = p; s != vrt_magic_string_end;
144 552
             s = va_arg(ap, const char *))
145 552
                if (s != NULL && *s != '\0')
146 492
                        len += strlen(s);
147
148 460
        return(func[dec].decode_l(len));
149
}
150
151
static void
152 68
err_decode(VRT_CTX, const char *enc)
153
{
154 68
        switch (errno) {
155
        case EINVAL:
156 68
                ERRINVAL(ctx, enc);
157 68
                break;
158
        case ENOMEM:
159 0
                ERRNOMEM(ctx, "cannot decode");
160 0
                break;
161
        default:
162 0
                WRONG("invalid errno");
163
        }
164 68
}
165
166
static inline int
167 1308
encodes_hex(enum encoding enc)
168
{
169 1308
        return (enc == HEX || enc == URL);
170
}
171
172
/* Require case DEFAULT for all encodings besides HEX and URL. */
173
174
static inline int
175 1256
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc,
176
               enum case_e kase)
177
{
178 1256
        if (!encodes_hex(enc) && kase != DEFAULT) {
179 32
                VERR(ctx, "case %s is illegal with encoding %s", case_s, encs);
180 32
                return 0;
181
        }
182 1224
        return 1;
183
}
184
185
/* Objects */
186
187
VCL_VOID v_matchproto_(td_blob_blob__init)
188 100
vmod_blob__init(VRT_CTX, struct vmod_blob_blob **blobp, const char *vcl_name,
189
                VCL_ENUM decs, const char *p, ...)
190
{
191
        struct vmod_blob_blob *b;
192 100
        enum encoding dec = parse_encoding(decs);
193
        va_list ap;
194
        ssize_t len;
195
196 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
197 100
        AN(blobp);
198 100
        AZ(*blobp);
199 100
        AN(vcl_name);
200 100
        AENC(dec);
201
202 100
        ALLOC_OBJ(b, VMOD_BLOB_MAGIC);
203 100
        AN(b);
204 100
        *blobp = b;
205 100
        b->blob.free = NULL;
206 100
        AZ(pthread_mutex_init(&b->lock, NULL));
207
208 100
        va_start(ap, p);
209 100
        len = decode_l_va(dec, p, ap);
210 100
        va_end(ap);
211 100
        if (len == 0) {
212 16
                b->blob.len = 0;
213 16
                b->blob.priv = NULL;
214 48
                return;
215
        }
216 84
        assert(len > 0);
217
218 84
        b->blob.priv = malloc(len);
219 84
        if (b->blob.priv == NULL) {
220 0
                VERRNOMEM(ctx, "cannot create blob %s", vcl_name);
221 0
                return;
222
        }
223
224 84
        va_start(ap, p);
225 84
        errno = 0;
226 84
        len = func[dec].decode(dec, b->blob.priv, len, -1, p, ap);
227 84
        va_end(ap);
228
229 84
        if (len == -1) {
230 16
                assert(errno == EINVAL);
231 16
                free(b->blob.priv);
232 16
                b->blob.priv = NULL;
233 16
                VERR(ctx, "cannot create blob %s, illegal encoding beginning "
234
                    "with \"%s\"", vcl_name, p);
235 16
                return;
236
        }
237 68
        if (len == 0) {
238 0
                b->blob.len = 0;
239 0
                free(b->blob.priv);
240 0
                b->blob.priv = NULL;
241 0
                return;
242
        }
243 68
        b->blob.len = len;
244
}
245
246
VCL_BLOB v_matchproto_(td_blob_blob_get)
247 214
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b)
248
{
249 214
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
250 214
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
251 214
        return &b->blob;
252
}
253
254
VCL_STRING v_matchproto_(td_blob_blob_encode)
255 354
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs,
256
                 VCL_ENUM case_s)
257
{
258 354
        enum encoding enc = parse_encoding(encs);
259 354
        AENC(enc);
260 354
        enum case_e kase = parse_case(case_s);
261
262 354
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
263 354
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
264
265 354
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
266 16
                return NULL;
267 338
        if (b->blob.len == 0)
268 40
                return "";
269 298
        if (kase == DEFAULT)
270 182
                kase = LOWER;
271
272 298
        if (b->encoding[enc][kase] == NULL) {
273 122
                AZ(pthread_mutex_lock(&b->lock));
274 122
                if (b->encoding[enc][kase] == NULL) {
275 122
                        ssize_t len = func[enc].encode_l(b->blob.len);
276
277 122
                        assert(len >= 0);
278 122
                        if (len == 0)
279 0
                                b->encoding[enc][kase] = empty;
280
                        else {
281 122
                                b->encoding[enc][kase] = malloc(len);
282 122
                                if (b->encoding[enc][kase] == NULL)
283 0
                                        ERRNOMEM(ctx, "cannot encode");
284
                                else {
285 122
                                        char *s = b->encoding[enc][kase];
286 122
                                        len =
287 366
                                                func[enc].encode(
288
                                                        enc, kase, s, len,
289 122
                                                        b->blob.priv,
290 122
                                                        b->blob.len);
291 122
                                        assert(len >= 0);
292 122
                                        if (len == 0) {
293 0
                                                free(s);
294 0
                                                b->encoding[enc][kase] = empty;
295
                                        }
296
                                        else
297 122
                                                s[len] = '\0';
298
                                }
299
                        }
300
                }
301 122
                AZ(pthread_mutex_unlock(&b->lock));
302
        }
303 298
        return b->encoding[enc][kase];
304
}
305
306
VCL_VOID v_matchproto_(td_blob_blob__fini)
307 34
vmod_blob__fini(struct vmod_blob_blob **blobp)
308
{
309
        struct vmod_blob_blob *b;
310
311 34
        if (blobp == NULL || *blobp == NULL)
312 40
                return;
313
314 28
        b = *blobp;
315 28
        *blobp = NULL;
316 28
        CHECK_OBJ(b, VMOD_BLOB_MAGIC);
317 28
        if (b->blob.priv != NULL) {
318 8
                free(b->blob.priv);
319 8
                b->blob.priv = NULL;
320
        }
321 224
        for (int i = 0; i < __MAX_ENCODING; i++)
322 588
                for (int j = 0; j < 2; j++) {
323 392
                        char *s = b->encoding[i][j];
324 392
                        if (s != NULL && s != empty) {
325 24
                                free(s);
326 24
                                b->encoding[i][j] = NULL;
327
                        }
328
                }
329 28
        AZ(pthread_mutex_destroy(&b->lock));
330 28
        FREE_OBJ(b);
331
}
332
333
/* Functions */
334
335
static inline const char *
336 8
find_nonempty_va(const char *restrict *p, va_list ap)
337
{
338
        const char *q;
339
340
        /* find first non-empty vararg */
341 16
        for (; *p == vrt_magic_string_end || *p == NULL || **p == '\0';
342 0
             *p = va_arg(ap, char *))
343 0
                if (*p == vrt_magic_string_end)
344 0
                        return (vrt_magic_string_end);
345
346
        /* find next non-empty vararg */
347 16
        for (q = va_arg(ap, const char *);
348 8
             q != vrt_magic_string_end && (q == NULL || *q == '\0');
349 0
             q = va_arg(ap, const char *))
350
                ;
351
352 8
        return (q);
353
}
354
355
VCL_BLOB v_matchproto_(td_blob_decode)
356 458
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, const char *p, ...)
357
{
358 458
        enum encoding dec = parse_encoding(decs);
359
        va_list ap;
360
        struct wb_s wb;
361
        struct vmod_priv *b;
362
        char *buf;
363
        uintptr_t snap;
364
        ssize_t len;
365
366 458
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
367 458
        AENC(dec);
368 458
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
369
370 458
        snap = WS_Snapshot(ctx->ws);
371 458
        if ((b = WS_Alloc(ctx->ws, sizeof(struct vmod_priv))) == NULL) {
372 0
                ERRNOMEM(ctx, "cannot decode");
373 0
                return NULL;
374
        }
375
376 458
        if (wb_create(ctx->ws, &wb) == NULL) {
377 0
                WS_Reset(ctx->ws, snap);
378 0
                ERRNOMEM(ctx, "cannot decode");
379 0
                return NULL;
380
        }
381 458
        buf = wb_buf(&wb);
382
383 458
        if (length <= 0)
384 296
                length = -1;
385 458
        va_start(ap, p);
386 458
        errno = 0;
387 458
        len = func[dec].decode(dec, buf, wb_space(&wb), length, p, ap);
388 458
        va_end(ap);
389
390 458
        if (len == -1) {
391 28
                err_decode(ctx, p);
392 28
                wb_reset(&wb);
393 28
                WS_Reset(ctx->ws, snap);
394 28
                return NULL;
395
        }
396 430
        if (len == 0) {
397 78
                wb_reset(&wb);
398 78
                WS_Reset(ctx->ws, snap);
399 78
                return null_blob;
400
        }
401 352
        wb_advance(&wb, len);
402 352
        WS_ReleaseP(ctx->ws, wb_buf(&wb));
403 352
        b->priv = buf;
404 352
        b->len = len;
405 352
        b->free = NULL;
406 352
        return (b);
407
}
408
409
static VCL_STRING
410 838
encode(VRT_CTX, enum encoding enc, enum case_e kase, VCL_BLOB b)
411
{
412
        struct wb_s wb;
413
        ssize_t len;
414
415 838
        AENC(enc);
416
417 838
        if (b == NULL)
418 34
                return NULL;
419
420 804
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
421 804
        if (wb_create(ctx->ws, &wb) == NULL) {
422 2
                ERRNOMEM(ctx, "cannot encode");
423 2
                return NULL;
424
        }
425
426 2406
        len = func[enc].encode(enc, kase,
427 1604
                               wb_buf(&wb), wb_space(&wb), b->priv, b->len);
428
429 802
        if (len == -1) {
430 0
                ERRNOMEM(ctx, "cannot encode");
431 0
                wb_reset(&wb);
432 0
                return NULL;
433
        }
434 802
        if (len == 0) {
435 72
                wb_reset(&wb);
436 72
                return "";
437
        }
438 730
        wb_advance(&wb, len);
439 730
        return wb_finish(&wb, NULL);
440
}
441
442
VCL_STRING v_matchproto_(td_blob_encode)
443 542
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b)
444
{
445 542
        enum encoding enc = parse_encoding(encs);
446 542
        enum case_e kase = parse_case(case_s);
447
448 542
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
449 542
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
450 16
                return NULL;
451 526
        return encode(ctx, enc, kase, b);
452
}
453
454
VCL_STRING v_matchproto_(td_blob_transcode)
455 360
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s,
456
               VCL_INT length, const char *p, ...)
457
{
458 360
        enum encoding dec = parse_encoding(decs);
459 360
        enum encoding enc = parse_encoding(encs);
460 360
        enum case_e kase = parse_case(case_s);
461
        va_list ap;
462
        struct vmod_priv b;
463
        VCL_STRING r;
464
465 360
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
466 360
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
467
468 360
        AENC(dec);
469 360
        AENC(enc);
470
471 360
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
472 0
                return NULL;
473
474
        /*
475
         * Allocate space for the decoded blob on the stack
476
         * ignoring the limitation imposed by n
477
         */
478 360
        va_start(ap, p);
479 360
        size_t l = decode_l_va(dec, p, ap);
480 360
        va_end(ap);
481 360
        if (l == 0)
482 0
                return "";
483
        /* XXX: handle stack overflow? */
484 360
        char buf[l];
485 360
        b.free = NULL;
486 360
        b.priv = buf;
487
488 360
        if (length <= 0)
489 190
                length = -1;
490 360
        va_start(ap, p);
491 360
        errno = 0;
492 360
        b.len = func[dec].decode(dec, buf, l, length, p, ap);
493 360
        va_end(ap);
494
495 360
        if (b.len == -1) {
496 40
                err_decode(ctx, p);
497 40
                return NULL;
498
        }
499
500
        /*
501
         * If the encoding and decoding are the same, and the decoding was
502
         * legal, just return the string, if there was only one in the
503
         * STRING_LIST, or else the concatenated string.
504
         * For encodings with hex digits, we cannot assume the same result.
505
         * since the call may specify upper- or lower-case that differs
506
         * from the encoded string.
507
         */
508 320
        if (length == -1 && enc == dec && !encodes_hex(enc)) {
509 8
                const char *q, *pp = p;
510 8
                va_start(ap, p);
511 8
                q = find_nonempty_va(&pp, ap);
512 8
                va_end(ap);
513
514 8
                if (pp == vrt_magic_string_end)
515 0
                        return "";
516
517 8
                if (q == vrt_magic_string_end)
518 8
                        return pp;
519
520 0
                r = VRT_String(ctx->ws, NULL, p, ap);
521 0
                return r;
522
        }
523
524 312
        r = encode(ctx, enc, kase, &b);
525 312
        return (r);
526
}
527
528
VCL_BOOL v_matchproto_(td_blob_same)
529 36
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
530
{
531
        (void) ctx;
532
533 36
        if (b1 == NULL && b2 == NULL)
534 0
                return 1;
535 36
        if (b1 == NULL || b2 == NULL)
536 6
                return 0;
537 30
        return (b1->len == b2->len && b1->priv == b2->priv);
538
}
539
540
VCL_BOOL v_matchproto_(td_blob_equal)
541 24
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
542
{
543
        (void) ctx;
544
545 24
        if (b1 == NULL && b2 == NULL)
546 0
                return 1;
547 24
        if (b1 == NULL || b2 == NULL)
548 0
                return 0;
549 24
        if (b1->len != b2->len)
550 6
                return 0;
551 18
        if (b1->priv == b2->priv)
552 10
                return 1;
553 8
        if (b1->priv == NULL || b2->priv == NULL)
554 0
                return 0;
555 8
        return (memcmp(b1->priv, b2->priv, b1->len) == 0);
556
}
557
558
VCL_INT v_matchproto_(td_blob_length)
559 14
vmod_length(VRT_CTX, VCL_BLOB b)
560
{
561
        (void) ctx;
562
563 14
        if (b == NULL)
564 0
                return 0;
565 14
        return b->len;
566
}
567
568
VCL_BLOB v_matchproto_(td_blob_sub)
569 28
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off)
570
{
571
        uintptr_t snap;
572
        struct vmod_priv *sub;
573
574 28
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
575 28
        assert(n >= 0);
576 28
        assert(off >= 0);
577
578 28
        if (b == NULL || b->len == 0 || b->priv == NULL) {
579 4
                ERR(ctx, "blob is empty in blob.sub()");
580 4
                return NULL;
581
        }
582 24
        assert(b->len >= 0);
583 24
        if (off + n > b->len) {
584 8
                VERR(ctx, "size %lld from offset %lld requires more bytes than "
585
                     "blob length %d in blob.sub()", n, off, b->len);
586 8
                return NULL;
587
        }
588
589 16
        if (n == 0)
590 4
                return null_blob;
591
592 12
        snap = WS_Snapshot(ctx->ws);
593 12
        if ((sub = WS_Alloc(ctx->ws, sizeof(*sub))) == NULL) {
594 0
                ERRNOMEM(ctx, "Allocating BLOB result in blob.sub()");
595 0
                return NULL;
596
        }
597 12
        if ((sub->priv = WS_Alloc(ctx->ws, n)) == NULL) {
598 0
                VERRNOMEM(ctx, "Allocating %lld bytes in blob.sub()", n);
599 0
                WS_Reset(ctx->ws, snap);
600 0
                return NULL;
601
        }
602 12
        memcpy(sub->priv, (char *)b->priv + off, n);
603 12
        sub->len = n;
604 12
        return sub;
605
}