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");

Reply via email to