From b42288f9e56fbdaac79312a81310c51da0dbaa6b Mon Sep 17 00:00:00 2001 From: claudio Date: Wed, 3 May 2023 07:56:05 +0000 Subject: [PATCH] Introduce json_do_string() a function that JSON escapes a string. Implement json_do_printf() using json_do_string() and vasprintf(). json_do_string() only escapes the basic control chars (\b, \f, \n, \r and \t) other control chars are considered an error. Also the forward slash is not escaped since the JSON data is not embedded into HTML or XML. With feedback from tb@ & millert@ OK tb@ --- usr.sbin/rpki-client/json.c | 56 +++++++++++++++++++++++++++++++++---- usr.sbin/rpki-client/json.h | 3 +- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/usr.sbin/rpki-client/json.c b/usr.sbin/rpki-client/json.c index 6e065648ec9..5d860729ef2 100644 --- a/usr.sbin/rpki-client/json.c +++ b/usr.sbin/rpki-client/json.c @@ -1,4 +1,4 @@ -/* $OpenBSD: json.c,v 1.1 2023/04/27 07:57:25 claudio Exp $ */ +/* $OpenBSD: json.c,v 1.2 2023/05/03 07:56:05 claudio Exp $ */ /* * Copyright (c) 2020 Claudio Jeker @@ -16,10 +16,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include #include +#include #include #include "json.h" @@ -179,16 +181,58 @@ void json_do_printf(const char *name, const char *fmt, ...) { va_list ap; + char *str; - do_comma_indent(); + va_start(ap, fmt); + if (!eb) { + if (vasprintf(&str, fmt, ap) == -1) + errx(1, "json printf failed"); + json_do_string(name, str); + free(str); + } + va_end(ap); +} +void +json_do_string(const char *name, const char *v) +{ + unsigned char c; + + do_comma_indent(); do_name(name); if (!eb) eb = fprintf(jsonfh, "\"") < 0; - va_start(ap, fmt); - if (!eb) - eb = vfprintf(jsonfh, fmt, ap) < 0; - va_end(ap); + while ((c = *v++) != '\0' && !eb) { + /* skip escaping '/' since our use case does not require it */ + switch(c) { + case '"': + eb = fprintf(jsonfh, "\\\"") < 0; + break; + case '\\': + eb = fprintf(jsonfh, "\\\\") < 0; + break; + case '\b': + eb = fprintf(jsonfh, "\\b") < 0; + break; + case '\f': + eb = fprintf(jsonfh, "\\f") < 0; + break; + case '\n': + eb = fprintf(jsonfh, "\\n") < 0; + break; + case '\r': + eb = fprintf(jsonfh, "\\r") < 0; + break; + case '\t': + eb = fprintf(jsonfh, "\\t") < 0; + break; + default: + if (iscntrl(c)) + errx(1, "bad control character in string"); + eb = putc(c, jsonfh) == EOF; + break; + } + } if (!eb) eb = fprintf(jsonfh, "\"") < 0; } diff --git a/usr.sbin/rpki-client/json.h b/usr.sbin/rpki-client/json.h index bd7cbf221c8..5eb8babef4c 100644 --- a/usr.sbin/rpki-client/json.h +++ b/usr.sbin/rpki-client/json.h @@ -1,4 +1,4 @@ -/* $OpenBSD: json.h,v 1.1 2023/04/27 07:57:25 claudio Exp $ */ +/* $OpenBSD: json.h,v 1.2 2023/05/03 07:56:05 claudio Exp $ */ /* * Copyright (c) 2020 Claudio Jeker @@ -26,6 +26,7 @@ void json_do_object(const char *); void json_do_end(void); void json_do_printf(const char *, const char *, ...) __attribute__((__format__ (printf, 2, 3))); +void json_do_string(const char *, const char *); void json_do_hexdump(const char *, void *, size_t); void json_do_bool(const char *, int); void json_do_uint(const char *, unsigned long long); -- 2.20.1