diff options
Diffstat (limited to 'src/engine-gpgsm.c')
-rw-r--r-- | src/engine-gpgsm.c | 170 |
1 files changed, 122 insertions, 48 deletions
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 476e9ef..e7e2a20 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -88,6 +88,8 @@ struct engine_gpgsm { engine_status_handler_t fnc; void *fnc_value; + gpgme_status_cb_t mon_cb; + void *mon_cb_value; } status; struct @@ -183,6 +185,8 @@ close_notify_handler (int fd, void *opaque) static gpgme_error_t default_inq_cb (engine_gpgsm_t gpgsm, const char *line) { + (void)gpgsm; + if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) { _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10)); @@ -235,7 +239,8 @@ gpgsm_release (void *engine) static gpgme_error_t -gpgsm_new (void **engine, const char *file_name, const char *home_dir) +gpgsm_new (void **engine, const char *file_name, const char *home_dir, + const char *version) { gpgme_error_t err = 0; engine_gpgsm_t gpgsm; @@ -248,9 +253,12 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) #endif char *dft_display = NULL; char dft_ttyname[64]; + char *env_tty = NULL; char *dft_ttytype = NULL; char *optstr; + (void)version; /* Not yet used. */ + gpgsm = calloc (1, sizeof *gpgsm); if (!gpgsm) return gpg_error_from_syserror (); @@ -403,11 +411,20 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) goto leave; } - if (isatty (1)) + err = _gpgme_getenv ("GPG_TTY", &env_tty); + if (isatty (1) || env_tty || err) { - int rc; + int rc = 0; - rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); + if (err) + goto leave; + else if (env_tty) + { + snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty); + free (env_tty); + } + else + rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); /* Even though isatty() returns 1, ttyname_r() may fail in many ways, e.g., when /dev/pts is not accessible under chroot. */ @@ -510,7 +527,7 @@ gpgsm_set_locale (void *engine, int category, const char *value) engine_gpgsm_t gpgsm = engine; gpgme_error_t err; char *optstr; - char *catstr; + const char *catstr; /* FIXME: If value is NULL, we need to reset the option to default. But we can't do this. So we error out here. GPGSM needs support @@ -558,10 +575,11 @@ gpgsm_set_locale (void *engine, int category, const char *value) static gpgme_error_t -gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, +gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, const char *cmd, engine_status_handler_t status_fnc, void *status_fnc_value) { + assuan_context_t ctx = gpgsm->assuan_ctx; gpg_error_t err, cb_err; char *line; size_t linelen; @@ -610,8 +628,15 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, *(rest++) = 0; r = _gpgme_parse_status (line + 2); + if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS) + { + /* Note that we call the monitor even if we do + * not know the status code (r < 0). */ + cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value, + line + 2, rest); + } - if (r >= 0 && status_fnc) + if (r >= 0 && status_fnc && !cb_err) cb_err = status_fnc (status_fnc_value, r, rest); } } @@ -647,6 +672,9 @@ gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type) _gpgme_io_close (gpgsm->message_cb.fd); break; } +#else + (void)gpgsm; + (void)fd_type; #endif } @@ -656,7 +684,7 @@ gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt) { gpg_error_t err = 0; char line[COMMANDLINELEN]; - char *which; + const char *which; iocb_data_t *iocb_data; #if USE_DESCRIPTOR_PASSING int dir; @@ -726,7 +754,7 @@ gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt) which, iocb_data->server_fd_str); #endif - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL); #if USE_DESCRIPTOR_PASSING leave_set_fd: @@ -805,8 +833,13 @@ status_handler (void *opaque, int fd) && (line[2] == '\0' || line[2] == ' ')) { if (gpgsm->status.fnc) - err = gpgsm->status.fnc (gpgsm->status.fnc_value, - GPGME_STATUS_EOF, ""); + { + char emptystring[1] = {0}; + err = gpgsm->status.fnc (gpgsm->status.fnc_value, + GPGME_STATUS_EOF, emptystring); + if (gpg_err_code (err) == GPG_ERR_FALSE) + err = 0; /* Drop special error code. */ + } if (!err && gpgsm->colon.fnc && gpgsm->colon.any) { @@ -957,7 +990,11 @@ status_handler (void *opaque, int fd) if (r >= 0) { if (gpgsm->status.fnc) - err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest); + { + err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest); + if (gpg_err_code (err) == GPG_ERR_FALSE) + err = 0; /* Drop special error code. */ + } } else fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest); @@ -1075,8 +1112,7 @@ gpgsm_reset (void *engine) need to reset the list of signers. Note that RESET does not reset OPTION commands. */ return (gpgsm->assuan_ctx - ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", - NULL, NULL) + ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL) : 0); } #endif @@ -1118,6 +1154,8 @@ gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret) char *line; int length = 8; /* "DELKEYS " */ + (void)allow_secret; + if (!fpr) return gpg_error (GPG_ERR_INV_VALUE); @@ -1180,7 +1218,6 @@ static gpgme_error_t set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[]) { gpgme_error_t err = 0; - assuan_context_t ctx = gpgsm->assuan_ctx; char *line; int linelen; int invalid_recipients = 0; @@ -1218,7 +1255,7 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[]) } strcpy (&line[10], fpr); - err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc, + err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc, gpgsm->status.fnc_value); /* FIXME: This requires more work. */ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) @@ -1249,7 +1286,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO) { - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + err = gpgsm_assuan_simple_command (gpgsm, "OPTION no-encrypt-to", NULL, NULL); if (err) return err; @@ -1422,29 +1459,51 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, static gpgme_error_t -gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor, +gpgsm_genkey (void *engine, + const char *userid, const char *algo, + unsigned long reserved, unsigned long expires, + gpgme_key_t key, unsigned int flags, + gpgme_data_t help_data, unsigned int extraflags, gpgme_data_t pubkey, gpgme_data_t seckey) { engine_gpgsm_t gpgsm = engine; gpgme_error_t err; - if (!gpgsm || !pubkey || seckey) + (void)reserved; + + if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - gpgsm->input_cb.data = help_data; - err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data)); - if (err) - return err; - gpgsm->output_cb.data = pubkey; - err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" - : map_data_enc (gpgsm->output_cb.data)); - if (err) - return err; - gpgsm_clear_fd (gpgsm, MESSAGE_FD); - gpgsm->inline_data = NULL; + if (help_data) + { + if (!pubkey || seckey) + return gpg_error (GPG_ERR_INV_VALUE); - err = start (gpgsm, "GENKEY"); - return err; + gpgsm->input_cb.data = help_data; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data)); + if (err) + return err; + gpgsm->output_cb.data = pubkey; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, + (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor" + : map_data_enc (gpgsm->output_cb.data)); + if (err) + return err; + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + gpgsm->inline_data = NULL; + + err = start (gpgsm, "GENKEY"); + return err; + } + + (void)userid; + (void)algo; + (void)expires; + (void)key; + (void)flags; + + /* The new interface has not yet been implemented, */ + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } @@ -1472,8 +1531,7 @@ gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) /* Fist check whether the engine already features the --re-import option. */ err = gpgsm_assuan_simple_command - (gpgsm->assuan_ctx, - "GETINFO cmd_has_option IMPORT re-import", NULL, NULL); + (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL); if (err) return gpg_error (GPG_ERR_NOT_SUPPORTED); @@ -1575,13 +1633,12 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, available and thus there is no need for gpgsm to ask the agent whether a secret key exists for the public key. */ if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET)) - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check", - NULL, NULL); + gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL); /* Always send list-mode option because RESET does not reset it. */ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_syserror (); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL); free (line); if (err) return err; @@ -1591,24 +1648,24 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, /* Use the validation mode if requested. We don't check for an error yet because this is a pretty fresh gpgsm features. */ - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_VALIDATE)? "OPTION with-validation=1": "OPTION with-validation=0" , NULL, NULL); /* Include the ephemeral keys if requested. We don't check for an error yet because this is a pretty fresh gpgsm features. */ - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_EPHEMERAL)? "OPTION with-ephemeral-keys=1": "OPTION with-ephemeral-keys=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_WITH_SECRET)? "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? "OPTION offline=1": "OPTION offline=0" , @@ -1665,7 +1722,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, /* Always send list-mode option because RESET does not reset it. */ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_syserror (); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL); free (line); if (err) return err; @@ -1673,17 +1730,17 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, /* Always send key validation because RESET does not reset it. */ /* Use the validation mode if required. We don't check for an error yet because this is a pretty fresh gpgsm features. */ - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_VALIDATE)? "OPTION with-validation=1": "OPTION with-validation=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_WITH_SECRET)? "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? "OPTION offline=1": "OPTION offline=0" , @@ -1784,6 +1841,8 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, int i; gpgme_key_t key; + (void)use_textmode; + if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); @@ -1797,8 +1856,7 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0) return gpg_error_from_syserror (); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd, - NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL); free (assuan_cmd); if (err) return err; @@ -1812,7 +1870,7 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, char buf[100]; strcpy (stpcpy (buf, "SIGNER "), s); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf, + err = gpgsm_assuan_simple_command (gpgsm, buf, gpgsm->status.fnc, gpgsm->status.fnc_value); } @@ -1913,6 +1971,17 @@ gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags) } +/* This sets a status callback for monitoring status lines before they + * are passed to a caller set handler. */ +static void +gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value) +{ + engine_gpgsm_t gpgsm = engine; + + gpgsm->status.mon_cb = cb; + gpgsm->status.mon_cb_value = cb_value; +} + static void gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc, @@ -1966,6 +2035,8 @@ gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags) gpgme_error_t err; char *line; + (void)flags; + if (!key || !key->subkeys || !key->subkeys->fpr) return gpg_error (GPG_ERR_INV_CERT_OBJ); @@ -2001,6 +2072,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm = #else NULL, /* reset */ #endif + gpgsm_set_status_cb, gpgsm_set_status_handler, NULL, /* set_command_handler */ gpgsm_set_colon_line_handler, @@ -2018,6 +2090,8 @@ struct engine_ops _gpgme_engine_ops_gpgsm = gpgsm_import, gpgsm_keylist, gpgsm_keylist_ext, + NULL, /* keysign */ + NULL, /* tofu_policy */ gpgsm_sign, NULL, /* trustlist */ gpgsm_verify, |