summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2024-10-23 10:40:36 +0200
committerWerner Koch <wk@gnupg.org>2024-10-23 11:43:08 +0200
commit18081e2ecf43de2be6ad5a7ca3384e1e2b66914d (patch)
tree85aa3365b947da5bc7da0cea5610a60da6517eb3
parentagent: Fix resource leak for PRIMARY_CTX. (diff)
downloadgnupg2-18081e2ecf43de2be6ad5a7ca3384e1e2b66914d.tar.xz
gnupg2-18081e2ecf43de2be6ad5a7ca3384e1e2b66914d.zip
gpgsm: Terminate key listing on output write error.
* sm/keylist.c (list_internal_keys): Detect write errors to the output stream. * sm/server.c (any_failure_printed): New var. (gpgsm_status2): Handle new var. Move statusfp init to ... (gpgsm_init_statusfp): new function. (gpgsm_exit_failure_status): New. * sm/gpgsm.c (main): Explicit statusfp init. (gpgsm_exit): Print failure status on error. -- Test by using gpgsm -k >/dev/full gpgsm -k --wit-colons >/dev/full and also by redirecting to a file on a small partition. GnuPG-bug-id: 6185
-rw-r--r--sm/gpgsm.c10
-rw-r--r--sm/gpgsm.h2
-rw-r--r--sm/keylist.c15
-rw-r--r--sm/server.c62
4 files changed, 74 insertions, 15 deletions
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index 26b05773c..bea0184e3 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -1803,6 +1803,10 @@ main ( int argc, char **argv)
gnupg_inhibit_set_foregound_window (1);
}
+ /* Better make sure that we have a statusfp so that a failure status
+ * in gpgsm_exit can work even w/o any preeding status messages. */
+ gpgsm_init_statusfp (&ctrl);
+
/* Add default keybox. */
if (!nrings && default_keyring && !opt.use_keyboxd)
{
@@ -2356,6 +2360,12 @@ gpgsm_exit (int rc)
else if (opt.assert_signer_list && !assert_signer_true)
rc = 1;
+ /* If we had an error but not printed an error message, do it now.
+ * Note that the function will never print a second failure status
+ * line. */
+ if (rc)
+ gpgsm_exit_failure_status ();
+
gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
if (opt.debug & DBG_MEMSTAT_VALUE)
{
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 916d0235c..cd45ec101 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -355,12 +355,14 @@ int gpgsm_parse_validation_model (const char *model);
/*-- server.c --*/
void gpgsm_server (certlist_t default_recplist);
+void gpgsm_init_statusfp (ctrl_t ctrl);
gpg_error_t gpgsm_status (ctrl_t ctrl, int no, const char *text);
gpg_error_t gpgsm_status2 (ctrl_t ctrl, int no, ...) GPGRT_ATTR_SENTINEL(0);
gpg_error_t gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
gpg_err_code_t ec);
gpg_error_t gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
gpg_error_t err);
+void gpgsm_exit_failure_status (void);
gpg_error_t gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total);
gpg_error_t gpgsm_proxy_pinentry_notify (ctrl_t ctrl,
const unsigned char *line);
diff --git a/sm/keylist.c b/sm/keylist.c
index a29c7d792..41e7ca309 100644
--- a/sm/keylist.c
+++ b/sm/keylist.c
@@ -1663,6 +1663,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
resname = keydb_get_resource_name (hd);
+ es_clearerr (fp);
if (lastresname != resname )
{
int i;
@@ -1716,6 +1717,20 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
ksba_cert_release (lastcert);
lastcert = cert;
cert = NULL;
+
+ if (es_ferror (fp))
+ rc = gpg_error_from_syserror ();
+
+ /* For faster key listings we flush the output after each cert
+ * only if we list secret keys. */
+ if ((mode & 2) && es_fflush (fp) && !rc)
+ rc = gpg_error_from_syserror ();
+
+ if (rc)
+ {
+ log_error (_("error writing to output: %s\n"), gpg_strerror (rc));
+ goto leave;
+ }
}
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
rc = 0;
diff --git a/sm/server.c b/sm/server.c
index cb3fae24d..345c3167b 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -37,6 +37,11 @@
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
+/* Used to track whether we printed any FAILURE status in non-server
+ * mode. */
+static int any_failure_printed;
+
+
/* The filepointer for status message used in non-server mode */
static FILE *statusfp;
@@ -1515,6 +1520,24 @@ gpgsm_server (certlist_t default_recplist)
}
+void
+gpgsm_init_statusfp (ctrl_t ctrl)
+{
+ if (statusfp || ctrl->status_fd == -1)
+ return;
+
+ if (ctrl->status_fd == 1)
+ statusfp = stdout;
+ else if (ctrl->status_fd == 2)
+ statusfp = stderr;
+ else
+ statusfp = fdopen (ctrl->status_fd, "w");
+
+ if (!statusfp)
+ log_fatal ("can't open fd %d for status output: %s\n",
+ ctrl->status_fd, strerror(errno));
+}
+
gpg_error_t
gpgsm_status2 (ctrl_t ctrl, int no, ...)
@@ -1527,23 +1550,11 @@ gpgsm_status2 (ctrl_t ctrl, int no, ...)
if (ctrl->no_server && ctrl->status_fd == -1)
; /* No status wanted. */
+ else if (ctrl->no_server && no == STATUS_FAILURE && any_failure_printed)
+ ; /* Don't emit FAILURE a second time. */
else if (ctrl->no_server)
{
- if (!statusfp)
- {
- if (ctrl->status_fd == 1)
- statusfp = stdout;
- else if (ctrl->status_fd == 2)
- statusfp = stderr;
- else
- statusfp = fdopen (ctrl->status_fd, "w");
-
- if (!statusfp)
- {
- log_fatal ("can't open fd %d for status output: %s\n",
- ctrl->status_fd, strerror(errno));
- }
- }
+ gpgsm_init_statusfp (ctrl);
fputs ("[GNUPG:] ", statusfp);
fputs (get_status_string (no), statusfp);
@@ -1562,6 +1573,10 @@ gpgsm_status2 (ctrl_t ctrl, int no, ...)
}
}
putc ('\n', statusfp);
+
+ if (no == STATUS_FAILURE)
+ any_failure_printed = 1;
+
if (ferror (statusfp))
err = gpg_error_from_syserror ();
else
@@ -1614,6 +1629,23 @@ gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
}
+/* Function to print a FAILURE status line on exit. */
+void
+gpgsm_exit_failure_status (void)
+{
+ /* stderr is used as a last but possible wrong resort if no status
+ * has yet been printed. */
+ FILE *fp = statusfp? statusfp : stderr;
+
+ if (any_failure_printed)
+ return;
+
+ fputs ("[GNUPG:] ", fp);
+ fputs (get_status_string (STATUS_FAILURE), fp);
+ fputs (" gpgsm-exit 50331649\n", fp);
+}
+
+
/* This callback is used to emit progress status lines. */
gpg_error_t
gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total)