On 16 Feb 2022, at 8:16 am, Wietse Venema <wie...@porcupine.org> wrote:
> postqueue -j | jq -r ' > # See JSON OBJECT FORMAT section in the postqueue(1) manpage > select(.queue_name == "deferred") > | .queue_id > ' | postsuper -h - While we're on the topic of JSON output, FWIW, I am not convinced that the recent change to protect downstream consumers of JSON from non-printable content in "postqueue -j" output (which is robustly escaped in its JSON representation) was the right choice. 20211027 Safety: the postqueue command now sanitizes strings before they are formatted as json output or legacy output. These outputs are piped into other programs that are run by administrative users. This closes a hypothetical opportunity for privilege escalation. Files: util/attr.h, util/attr_scan*.c, postqueue/showq_json.c, postqueue/showq_compat.c. IMHO any responsibility to handle unexpected string payloads falls squarely on the JSON consumer, not showq(8) or postqueue(1). Sure, use of "jq -r" exposes unescaped output and the user should be warned to expect the unexpected. Alternatively, perhaps there should be an option to turn off the safety net. Something like the '-J' option below (with appropriate documentation and warnings). -- Viktor. diff --git a/src/postqueue/postqueue.c b/src/postqueue/postqueue.c index 09e5bcaf8..7bad79d2e 100644 --- a/src/postqueue/postqueue.c +++ b/src/postqueue/postqueue.c @@ -323,6 +323,7 @@ #define PQ_MODE_FLUSH_SITE 3 /* flush site */ #define PQ_MODE_FLUSH_FILE 4 /* flush message */ #define PQ_MODE_JSON_LIST 5 /* JSON-format queue listing */ +#define PQ_MODE_JSON_RAW 6 /* JSON-format queue listing (raw) */ /* * Silly little macros (SLMs). @@ -341,6 +342,9 @@ static const CONFIG_STR_TABLE str_table[] = { 0, }; +#define RAW_JSON 0 +#define SANITISED_JSON 1 + /* showq_client - run the appropriate showq protocol client */ static void showq_client(int mode, VSTREAM *showq) @@ -354,7 +358,10 @@ static void showq_client(int mode, VSTREAM *showq) showq_compat(showq); break; case PQ_MODE_JSON_LIST: - showq_json(showq); + showq_json(showq, SANITISED_JSON); + break; + case PQ_MODE_JSON_RAW: + showq_json(showq, RAW_JSON); break; default: msg_panic("show_queue: unknown mode %d", mode); @@ -605,7 +612,7 @@ int main(int argc, char **argv) * mail configuration read routine. Don't do complex things until we have * completed initializations. */ - while ((c = GETOPT(argc, argv, "c:fi:jps:v")) > 0) { + while ((c = GETOPT(argc, argv, "c:fi:jJps:v")) > 0) { switch (c) { case 'c': /* non-default configuration */ if (setenv(CONF_ENV_PATH, optarg, 1) < 0) @@ -627,6 +634,11 @@ int main(int argc, char **argv) usage(); mode = PQ_MODE_JSON_LIST; break; + case 'J': + if (mode != PQ_MODE_DEFAULT) + usage(); + mode = PQ_MODE_JSON_RAW; + break; case 'p': /* traditional mailq */ if (mode != PQ_MODE_DEFAULT) usage(); @@ -705,6 +717,7 @@ int main(int argc, char **argv) /* NOTREACHED */ case PQ_MODE_MAILQ_LIST: case PQ_MODE_JSON_LIST: + case PQ_MODE_JSON_RAW: show_queue(mode); exit(0); break; diff --git a/src/postqueue/showq_json.c b/src/postqueue/showq_json.c index fc205c726..f2e60f622 100644 --- a/src/postqueue/showq_json.c +++ b/src/postqueue/showq_json.c @@ -123,7 +123,7 @@ static char *json_quote(VSTRING *result, const char *text) /* json_message - report status for one message */ -static void format_json(VSTREAM *showq_stream) +static void format_json(VSTREAM *showq_stream, int sanitise) { static VSTRING *queue_name = 0; static VSTRING *queue_id = 0; @@ -151,7 +151,7 @@ static void format_json(VSTREAM *showq_stream) * Read the message properties and sender address. */ if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT - | ATTR_FLAG_PRINTABLE, + | (sanitise ? ATTR_FLAG_PRINTABLE : 0), RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name), RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id), RECV_ATTR_LONG(MAIL_ATTR_TIME, &arrival_time), @@ -204,7 +204,7 @@ static void format_json(VSTREAM *showq_stream) /* showq_json - streaming JSON-format output adapter */ -void showq_json(VSTREAM *showq_stream) +void showq_json(VSTREAM *showq_stream, int sanitise) { int showq_status; @@ -214,7 +214,7 @@ void showq_json(VSTREAM *showq_stream) */ while ((showq_status = attr_scan_more(showq_stream)) > 0 && vstream_ferror(VSTREAM_OUT) == 0) { - format_json(showq_stream); + format_json(showq_stream, sanitise); } if (showq_status < 0) msg_fatal_status(EX_SOFTWARE, "malformed showq server response");