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 3420
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 1974
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 690
decode_l_va(enum encoding dec, const char * const p, va_list ap)
137
{
138 690
        size_t len = 0;
139
140 690
        AENC(dec);
141
142 2208
        for (const char *s = p; s != vrt_magic_string_end;
143 828
             s = va_arg(ap, const char *))
144 828
                if (s != NULL && *s != '\0')
145 738
                        len += strlen(s);
146
147 690
        return(func[dec].decode_l(len));
148
}
149
150
static void
151 114
err_decode(VRT_CTX, const char *enc)
152
{
153 114
        switch (errno) {
154
        case EINVAL:
155 102
                ERRINVAL(ctx, enc);
156 102
                break;
157
        case ENOMEM:
158 12
                ERRNOMEM(ctx, "cannot decode");
159 12
                break;
160
        default:
161 0
                WRONG("invalid errno");
162
        }
163 114
}
164
165
static inline int
166 2052
encodes_hex(enum encoding enc)
167
{
168 2052
        return (enc == HEX || enc == URL);
169
}
170
171
/* Require case DEFAULT for all encodings besides HEX and URL. */
172
173
static inline int
174 1974
check_enc_case(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, enum encoding enc,
175
               enum case_e kase)
176
{
177 1974
        if (!encodes_hex(enc) && kase != DEFAULT) {
178 48
                VERR(ctx, "case %s is illegal with encoding %s", case_s, encs);
179 48
                return 0;
180
        }
181 1926
        return 1;
182
}
183
184
/* Objects */
185
186
VCL_VOID v_matchproto_(td_blob_blob__init)
187 150
vmod_blob__init(VRT_CTX, struct vmod_blob_blob **blobp, const char *vcl_name,
188
                VCL_ENUM decs, const char *p, ...)
189
{
190
        struct vmod_blob_blob *b;
191 150
        enum encoding dec = parse_encoding(decs);
192
        va_list ap;
193
        ssize_t len;
194
195 150
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
196 150
        AN(blobp);
197 150
        AZ(*blobp);
198 150
        AN(vcl_name);
199 150
        AENC(dec);
200
201 150
        ALLOC_OBJ(b, VMOD_BLOB_MAGIC);
202 150
        AN(b);
203 150
        *blobp = b;
204 150
        b->blob.free = NULL;
205 150
        AZ(pthread_mutex_init(&b->lock, NULL));
206
207 150
        va_start(ap, p);
208 150
        len = decode_l_va(dec, p, ap);
209 150
        va_end(ap);
210 150
        if (len == 0) {
211 24
                b->blob.len = 0;
212 24
                b->blob.priv = NULL;
213 72
                return;
214
        }
215 126
        assert(len > 0);
216
217 126
        b->blob.priv = malloc(len);
218 126
        if (b->blob.priv == NULL) {
219 0
                VERRNOMEM(ctx, "cannot create blob %s", vcl_name);
220 0
                return;
221
        }
222
223 126
        va_start(ap, p);
224 126
        errno = 0;
225 126
        len = func[dec].decode(dec, b->blob.priv, len, -1, p, ap);
226 126
        va_end(ap);
227
228 126
        if (len == -1) {
229 24
                assert(errno == EINVAL);
230 24
                free(b->blob.priv);
231 24
                b->blob.priv = NULL;
232 24
                VERR(ctx, "cannot create blob %s, illegal encoding beginning "
233
                    "with \"%s\"", vcl_name, p);
234 24
                return;
235
        }
236 102
        if (len == 0) {
237 0
                b->blob.len = 0;
238 0
                free(b->blob.priv);
239 0
                b->blob.priv = NULL;
240 0
                return;
241
        }
242 102
        b->blob.len = len;
243
}
244
245
VCL_BLOB v_matchproto_(td_blob_blob_get)
246 321
vmod_blob_get(VRT_CTX, struct vmod_blob_blob *b)
247
{
248 321
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
249 321
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
250 321
        return &b->blob;
251
}
252
253
VCL_STRING v_matchproto_(td_blob_blob_encode)
254 531
vmod_blob_encode(VRT_CTX, struct vmod_blob_blob *b, VCL_ENUM encs,
255
                 VCL_ENUM case_s)
256
{
257 531
        enum encoding enc = parse_encoding(encs);
258 531
        AENC(enc);
259 531
        enum case_e kase = parse_case(case_s);
260
261 531
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
262 531
        CHECK_OBJ_NOTNULL(b, VMOD_BLOB_MAGIC);
263
264 531
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
265 24
                return NULL;
266 507
        if (b->blob.len == 0)
267 60
                return "";
268 447
        if (kase == DEFAULT)
269 273
                kase = LOWER;
270
271 447
        if (b->encoding[enc][kase] == NULL) {
272 183
                AZ(pthread_mutex_lock(&b->lock));
273 183
                if (b->encoding[enc][kase] == NULL) {
274 183
                        ssize_t len = func[enc].encode_l(b->blob.len);
275
276 183
                        assert(len >= 0);
277 183
                        if (len == 0)
278 0
                                b->encoding[enc][kase] = empty;
279
                        else {
280 183
                                b->encoding[enc][kase] = malloc(len);
281 183
                                if (b->encoding[enc][kase] == NULL)
282 0
                                        ERRNOMEM(ctx, "cannot encode");
283
                                else {
284 183
                                        char *s = b->encoding[enc][kase];
285 183
                                        len =
286 549
                                                func[enc].encode(
287
                                                        enc, kase, s, len,
288 183
                                                        b->blob.priv,
289 183
                                                        b->blob.len);
290 183
                                        assert(len >= 0);
291 183
                                        if (len == 0) {
292 0
                                                free(s);
293 0
                                                b->encoding[enc][kase] = empty;
294
                                        }
295
                                        else
296 183
                                                s[len] = '\0';
297
                                }
298
                        }
299
                }
300 183
                AZ(pthread_mutex_unlock(&b->lock));
301
        }
302 447
        return b->encoding[enc][kase];
303
}
304
305
VCL_VOID v_matchproto_(td_blob_blob__fini)
306 51
vmod_blob__fini(struct vmod_blob_blob **blobp)
307
{
308
        struct vmod_blob_blob *b;
309
310 51
        if (blobp == NULL || *blobp == NULL)
311 9
                return;
312
313 42
        b = *blobp;
314 42
        *blobp = NULL;
315 42
        CHECK_OBJ(b, VMOD_BLOB_MAGIC);
316 42
        if (b->blob.priv != NULL) {
317 12
                free(b->blob.priv);
318 12
                b->blob.priv = NULL;
319
        }
320 336
        for (int i = 0; i < __MAX_ENCODING; i++)
321 882
                for (int j = 0; j < 2; j++) {
322 588
                        char *s = b->encoding[i][j];
323 588
                        if (s != NULL && s != empty) {
324 36
                                free(s);
325 36
                                b->encoding[i][j] = NULL;
326
                        }
327
                }
328 42
        AZ(pthread_mutex_destroy(&b->lock));
329 42
        FREE_OBJ(b);
330
}
331
332
/* Functions */
333
334
static inline const char *
335 12
find_nonempty_va(const char *restrict *p, va_list ap)
336
{
337
        const char *q;
338
339
        /* find first non-empty vararg */
340 24
        for (; *p == vrt_magic_string_end || *p == NULL || **p == '\0';
341 0
             *p = va_arg(ap, char *))
342 0
                if (*p == vrt_magic_string_end)
343 0
                        return (vrt_magic_string_end);
344
345
        /* find next non-empty vararg */
346 24
        for (q = va_arg(ap, const char *);
347 12
             q != vrt_magic_string_end && (q == NULL || *q == '\0');
348 0
             q = va_arg(ap, const char *))
349
                ;
350
351 12
        return (q);
352
}
353
354
VCL_BLOB v_matchproto_(td_blob_decode)
355 756
vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_INT length, const char *p, ...)
356
{
357 756
        enum encoding dec = parse_encoding(decs);
358
        va_list ap;
359
        struct vmod_priv *b;
360
        char *buf;
361
        uintptr_t snap;
362
        ssize_t len;
363
        unsigned space;
364
365 756
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
366 756
        AENC(dec);
367 756
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
368
369 756
        snap = WS_Snapshot(ctx->ws);
370 756
        if ((b = WS_Alloc(ctx->ws, sizeof(struct vmod_priv))) == NULL) {
371 3
                ERRNOMEM(ctx, "cannot decode");
372 3
                return NULL;
373
        }
374
375 753
        buf = WS_Front(ctx->ws);
376 753
        space = WS_Reserve(ctx->ws, 0);
377
378 753
        if (length <= 0)
379 510
                length = -1;
380 753
        va_start(ap, p);
381 753
        errno = 0;
382 753
        len = func[dec].decode(dec, buf, space, length, p, ap);
383 753
        va_end(ap);
384
385 753
        if (len == -1) {
386 54
                err_decode(ctx, p);
387 54
                WS_Release(ctx->ws, 0);
388 54
                WS_Reset(ctx->ws, snap);
389 54
                return NULL;
390
        }
391 699
        if (len == 0) {
392 126
                WS_Release(ctx->ws, 0);
393 126
                WS_Reset(ctx->ws, snap);
394 126
                return null_blob;
395
        }
396 573
        WS_Release(ctx->ws, len);
397 573
        b->priv = buf;
398 573
        b->len = len;
399 573
        b->free = NULL;
400 573
        return (b);
401
}
402
403
static VCL_STRING
404 1347
encode(VRT_CTX, enum encoding enc, enum case_e kase, VCL_BLOB b)
405
{
406
        ssize_t len;
407
        char *buf;
408
        uintptr_t snap;
409
        unsigned space;
410
411 1347
        AENC(enc);
412
413 1347
        if (b == NULL)
414 72
                return NULL;
415
416 1275
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
417 1275
        snap = WS_Snapshot(ctx->ws);
418 1275
        buf = WS_Front(ctx->ws);
419 1275
        space = WS_Reserve(ctx->ws, 0);
420
421 1275
        len = func[enc].encode(enc, kase, buf, space, b->priv, b->len);
422
423 1275
        if (len == -1) {
424 27
                ERRNOMEM(ctx, "cannot encode");
425 27
                WS_Release(ctx->ws, 0);
426 27
                WS_Reset(ctx->ws, snap);
427 27
                return NULL;
428
        }
429 1248
        if (len == 0) {
430 108
                WS_Release(ctx->ws, 0);
431 108
                WS_Reset(ctx->ws, snap);
432 108
                return "";
433
        }
434 1140
        buf[len] = '\0';
435 1140
        WS_Release(ctx->ws, len + 1);
436 1140
        return buf;
437
}
438
439
VCL_STRING v_matchproto_(td_blob_encode)
440 903
vmod_encode(VRT_CTX, VCL_ENUM encs, VCL_ENUM case_s, VCL_BLOB b)
441
{
442 903
        enum encoding enc = parse_encoding(encs);
443 903
        enum case_e kase = parse_case(case_s);
444
445 903
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
446 903
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
447 24
                return NULL;
448 879
        return encode(ctx, enc, kase, b);
449
}
450
451
VCL_STRING v_matchproto_(td_blob_transcode)
452 540
vmod_transcode(VRT_CTX, VCL_ENUM decs, VCL_ENUM encs, VCL_ENUM case_s,
453
               VCL_INT length, const char *p, ...)
454 540
{
455 540
        enum encoding dec = parse_encoding(decs);
456 540
        enum encoding enc = parse_encoding(encs);
457 540
        enum case_e kase = parse_case(case_s);
458
        va_list ap;
459
        struct vmod_priv b;
460
        VCL_STRING r;
461
462 540
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
463 540
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
464
465 540
        AENC(dec);
466 540
        AENC(enc);
467
468 540
        if (!check_enc_case(ctx, encs, case_s, enc, kase))
469 0
                return NULL;
470
471
        /*
472
         * Allocate space for the decoded blob on the stack
473
         * ignoring the limitation imposed by n
474
         */
475 540
        va_start(ap, p);
476 540
        size_t l = decode_l_va(dec, p, ap);
477 540
        va_end(ap);
478 540
        if (l == 0)
479 0
                return "";
480
        /* XXX: handle stack overflow? */
481 540
        char buf[l];
482 540
        b.free = NULL;
483 540
        b.priv = buf;
484
485 540
        if (length <= 0)
486 285
                length = -1;
487 540
        va_start(ap, p);
488 540
        errno = 0;
489 540
        b.len = func[dec].decode(dec, buf, l, length, p, ap);
490 540
        va_end(ap);
491
492 540
        if (b.len == -1) {
493 60
                err_decode(ctx, p);
494 60
                return NULL;
495
        }
496
497
        /*
498
         * If the encoding and decoding are the same, and the decoding was
499
         * legal, just return the string, if there was only one in the
500
         * STRING_LIST, or else the concatenated string.
501
         * For encodings with hex digits, we cannot assume the same result.
502
         * since the call may specify upper- or lower-case that differs
503
         * from the encoded string.
504
         */
505 480
        if (length == -1 && enc == dec && !encodes_hex(enc)) {
506 12
                const char *q, *pp = p;
507 12
                va_start(ap, p);
508 12
                q = find_nonempty_va(&pp, ap);
509 12
                va_end(ap);
510
511 12
                if (pp == vrt_magic_string_end)
512 0
                        return "";
513
514 12
                if (q == vrt_magic_string_end)
515 12
                        return pp;
516
517 0
                r = VRT_String(ctx->ws, NULL, p, ap);
518 0
                return r;
519
        }
520
521 468
        r = encode(ctx, enc, kase, &b);
522 468
        return (r);
523
}
524
525
VCL_BOOL v_matchproto_(td_blob_same)
526 54
vmod_same(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
527
{
528
        (void) ctx;
529
530 54
        if (b1 == NULL && b2 == NULL)
531 0
                return 1;
532 54
        if (b1 == NULL || b2 == NULL)
533 9
                return 0;
534 45
        return (b1->len == b2->len && b1->priv == b2->priv);
535
}
536
537
VCL_BOOL v_matchproto_(td_blob_equal)
538 36
vmod_equal(VRT_CTX, VCL_BLOB b1, VCL_BLOB b2)
539
{
540
        (void) ctx;
541
542 36
        if (b1 == NULL && b2 == NULL)
543 0
                return 1;
544 36
        if (b1 == NULL || b2 == NULL)
545 0
                return 0;
546 36
        if (b1->len != b2->len)
547 9
                return 0;
548 27
        if (b1->priv == b2->priv)
549 15
                return 1;
550 12
        if (b1->priv == NULL || b2->priv == NULL)
551 0
                return 0;
552 12
        return (memcmp(b1->priv, b2->priv, b1->len) == 0);
553
}
554
555
VCL_INT v_matchproto_(td_blob_length)
556 21
vmod_length(VRT_CTX, VCL_BLOB b)
557
{
558
        (void) ctx;
559
560 21
        if (b == NULL)
561 0
                return 0;
562 21
        return b->len;
563
}
564
565
VCL_BLOB v_matchproto_(td_blob_sub)
566 48
vmod_sub(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off)
567
{
568
        uintptr_t snap;
569
        struct vmod_priv *sub;
570
571 48
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
572 48
        assert(n >= 0);
573 48
        assert(off >= 0);
574
575 48
        if (b == NULL || b->len == 0 || b->priv == NULL) {
576 6
                ERR(ctx, "blob is empty in blob.sub()");
577 6
                return NULL;
578
        }
579 42
        assert(b->len >= 0);
580 42
        if (off + n > b->len) {
581 12
                VERR(ctx, "size %jd from offset %jd requires more bytes than "
582
                     "blob length %d in blob.sub()",
583
                     (intmax_t)n, (intmax_t)off, b->len);
584 12
                return NULL;
585
        }
586
587 30
        if (n == 0)
588 6
                return null_blob;
589
590 24
        snap = WS_Snapshot(ctx->ws);
591 24
        if ((sub = WS_Alloc(ctx->ws, sizeof(*sub))) == NULL) {
592 3
                ERRNOMEM(ctx, "Allocating BLOB result in blob.sub()");
593 3
                return NULL;
594
        }
595 21
        if ((sub->priv = WS_Alloc(ctx->ws, n)) == NULL) {
596 3
                VERRNOMEM(ctx, "Allocating %jd bytes in blob.sub()", (intmax_t)n);
597 3
                WS_Reset(ctx->ws, snap);
598 3
                return NULL;
599
        }
600 18
        memcpy(sub->priv, (char *)b->priv + off, n);
601 18
        sub->len = n;
602 18
        return sub;
603
}