From a4bf6cd6a4dca1e4c1484d1da39b3e3a1996bc4b Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Thu, 16 Apr 2009 21:34:42 -0400 Subject: [PATCH] Added pwmd_getpin(). This won't send any commands to the server. May be useful for remote pwmd connections. --- NEWS | 2 +- doc/libpwmd.3 | 47 +++++++++++++++++++++ doc/pwmc.1.in | 17 +++++++- po/libpwmd.pot | 44 ++++++++++++++++---- src/libpwmd.c | 14 ++++++- src/libpwmd.h.in | 38 +++++++++++++++++ src/pinentry.c | 76 ++++++++++++++++++++++------------ src/pinentry.h | 6 ++- src/pwmc.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++----- src/types.h | 7 ---- 10 files changed, 315 insertions(+), 58 deletions(-) diff --git a/NEWS b/NEWS index b4faa557..54c4f2c1 100644 --- a/NEWS +++ b/NEWS @@ -16,7 +16,7 @@ how pwmd_process() works. Here are the API changes: pwmd_ssh_connect(), pwmd_ssh_connect_async(), pwmd_get_hostkey(), pwmd_get_hostkey_async(), pwmd_strerror_r(), pwmd_open2(), pwmd_save2(), pwmd_connect_url(), pwmd_connect_url_async(), - pwmd_socket_type(), pwmd_disconnect() + pwmd_socket_type(), pwmd_disconnect(), pwmd_getpin() Options removed: PWMD_OPTION_PINENTRY Options added: PWMD_OPTION_IP_VERSION diff --git a/doc/libpwmd.3 b/doc/libpwmd.3 index 65a0515d..9e508a3a 100644 --- a/doc/libpwmd.3 +++ b/doc/libpwmd.3 @@ -191,6 +191,9 @@ The following example will list the element tree of the data file specified in t .RI "enum \fBpwmd_socket_t\fP { \fBPWMD_SOCKET_UDS\fP, \fBPWMD_SOCKET_SSH\fP }" .br .ti -1c +.RI "enum \fBpwmd_pinentry_t\fP { \fBPWMD_PINENTRY_OPEN\fP, \fBPWMD_PINENTRY_OPEN_FAILED\fP, \fBPWMD_PINENTRY_SAVE\fP, \fBPWMD_PINENTRY_SAVE_CONFIRM\fP }" +.br +.ti -1c .RI "enum \fBpwmd_option_t\fP { \fBPWMD_OPTION_PASSPHRASE_CB\fP, \fBPWMD_OPTION_PASSPHRASE_DATA\fP, \fBPWMD_OPTION_PASSPHRASE\fP, \fBPWMD_OPTION_PINENTRY_TRIES\fP, \fBPWMD_OPTION_PINENTRY_PATH\fP, \fBPWMD_OPTION_PINENTRY_TTY\fP, \fBPWMD_OPTION_PINENTRY_TERM\fP, \fBPWMD_OPTION_PINENTRY_DISPLAY\fP, \fBPWMD_OPTION_PINENTRY_TITLE\fP, \fBPWMD_OPTION_PINENTRY_PROMPT\fP, \fBPWMD_OPTION_PINENTRY_DESC\fP, \fBPWMD_OPTION_PINENTRY_LC_CTYPE\fP, \fBPWMD_OPTION_PINENTRY_LC_MESSAGES\fP, \fBPWMD_OPTION_PINENTRY_TIMEOUT\fP, \fBPWMD_OPTION_STATUS_CB\fP, \fBPWMD_OPTION_STATUS_DATA\fP, \fBPWMD_OPTION_IP_VERSION\fP }" .br .in -1c @@ -234,6 +237,9 @@ The following example will list the element tree of the data file specified in t .RI "gpg_error_t \fBpwmd_setopt\fP (\fBpwm_t\fP *pwm, \fBpwmd_option_t\fP opt,...)" .br .ti -1c +.RI "gpg_error_t \fBpwmd_getpin\fP (\fBpwm_t\fP *pwm, const char *filename, char **result, \fBpwmd_pinentry_t\fP which)" +.br +.ti -1c .RI "gpg_error_t \fBpwmd_open\fP (\fBpwm_t\fP *pwm, const char *filename)" .br .ti -1c @@ -565,6 +571,24 @@ This option must be set before a connection is made when not the default. .RE .PP +.SS "enum \fBpwmd_pinentry_t\fP" +.PP +For use with \fBpwmd_getpin()\fP. +.PP +\fBEnumerator: \fP +.in +1c +.TP +\fB\fIPWMD_PINENTRY_OPEN \fP\fP +When opening a file. +.TP +\fB\fIPWMD_PINENTRY_OPEN_FAILED \fP\fP +When opening a file failed. +.TP +\fB\fIPWMD_PINENTRY_SAVE \fP\fP +When saving a file. +.TP +\fB\fIPWMD_PINENTRY_SAVE_CONFIRM \fP\fP +For passphrase confirmation. .SS "enum \fBpwmd_socket_t\fP" .PP For use with \fBpwmd_socket_type()\fP. @@ -924,6 +948,29 @@ This key is needed for host verification of the remote pwmd server. You should b .RE .PP +.SS "gpg_error_t pwmd_getpin (\fBpwm_t\fP * pwm, const char * filename, char ** result, \fBpwmd_pinentry_t\fP which)" +.PP +Launch a local pinentry. +.PP +Does not send any command to the server. +.PP +\fBParameters:\fP +.RS 4 +\fIpwm\fP A handle. +.br +\fIfilename\fP The filename to use in the pinentry dialog strings. +.br +\fIresult\fP The entered value in the pinentry dialog which should be freed with \fBpwmd_free()\fP. +.br +\fIwhich\fP For setting the pinentry dialog strings. \fBpwmd_setopt()\fP may also be used to override the defaults. +.RE +.PP +\fBReturns:\fP +.RS 4 +0 on success or an error. +.RE +.PP + .SS "gpg_error_t pwmd_init (void)" .PP Initialize the library. diff --git a/doc/pwmc.1.in b/doc/pwmc.1.in index 4d8f6e26..968cda9f 100644 --- a/doc/pwmc.1.in +++ b/doc/pwmc.1.in @@ -15,7 +15,7 @@ \\$2 \(laURL: \\$1 \(ra\\$3 .. .if \n[.g] .mso www.tmac -.TH PWMD 1 "04 Apr 2009" "Password Manager Client" "Password Manager Client" +.TH PWMD 1 "16 Apr 2009" "Password Manager Client" "Password Manager Client" .SH NAME pwmc \- send a command to a pwmd server @@ -190,6 +190,21 @@ The number of seconds before will timeout while waiting for a passphrase. The default is 30. .TP +.I "\--local-pinentry" +Force using the local pinentry for passphrase retrieval. This has the same +effect as specifying +.B --passphrase +after the +.BR pinentry (1) +dialog is closed. + +.TP +.I "\--force-save" +Expire any cache entry on the server before saving. When used with +.B --local-pinentry, +the initial passphrase is also cleared. + +.TP .I "\--version" Version information. .TP diff --git a/po/libpwmd.pot b/po/libpwmd.pot index 8f705295..565fd2e9 100644 --- a/po/libpwmd.pot +++ b/po/libpwmd.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: bjk@luxsci.net\n" -"POT-Creation-Date: 2009-04-12 09:41-0400\n" +"POT-Creation-Date: 2009-04-16 19:43-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,31 +16,31 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/libpwmd.c:79 +#: src/libpwmd.c:74 msgid "Unknown error" msgstr "" -#: src/libpwmd.c:81 +#: src/libpwmd.c:76 msgid "No cache slots available" msgstr "" -#: src/libpwmd.c:83 +#: src/libpwmd.c:78 msgid "Recursion loop" msgstr "" -#: src/libpwmd.c:85 +#: src/libpwmd.c:80 msgid "No file is open" msgstr "" -#: src/libpwmd.c:87 +#: src/libpwmd.c:82 msgid "General LibXML error" msgstr "" -#: src/libpwmd.c:89 +#: src/libpwmd.c:84 msgid "File modified" msgstr "" -#: src/libpwmd.c:1364 +#: src/libpwmd.c:1226 msgid "Invalid passphrase, please try again." msgstr "" @@ -56,61 +56,87 @@ msgid "" "Usage: pwmc [options] [file]\n" " --debug \n" " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, 3=libpwmd async)\n" +"\n" " --tries \n" " number of pinentry tries before failing (3)\n" +"\n" " --host, -h \n" " connect to the specified hostname\n" +"\n" " --port\n" " alterate port (22)\n" +"\n" " --user\n" " SSH username (default is the invoking user)\n" +"\n" " --identity, -i \n" " SSH identity file\n" +"\n" " --known-hosts, -k \n" " known host's file (for server validation)\n" +"\n" " --get-hostkey, -g\n" " retrieve the remote SSH host key and exit\n" +"\n" " --ipv4, -4\n" " try connecting via IPv4 only\n" +"\n" " --ipv6, -6\n" " try connecting via IPv6 only\n" +"\n" " --url \n" " a url string to parse\n" +"\n" " --timeout \n" " pinentry timeout\n" +"\n" " --no-status\n" " disable showing of status messages from the server\n" +"\n" " --name, -n \n" " set the client name\n" +"\n" " --socket \n" " local socket to connect to (~/.pwmd/socket)\n" +"\n" " --passphrase, -P \n" " passphrase to use (disables pinentry use)\n" +"\n" " --pinentry \n" " the full path to the pinentry binary (server default)\n" +"\n" " --ttyname, -y \n" " tty that pinentry will use\n" +"\n" " --ttytype, -t \n" " pinentry terminal type (default is TERM)\n" +"\n" " --display, -d\n" " pinentry display (default is DISPLAY)\n" +"\n" " --lc-ctype \n" " locale setting for pinentry\n" +"\n" " --lc-messages \n" " locale setting for pinentry\n" +"\n" " --output-fd \n" " redirect command output to the specified file descriptor\n" +"\n" " --inquire-fd \n" " read inquire data from the specified file descriptor\n" +"\n" " --save, -S\n" " send the SAVE command before exiting\n" +"\n" " --iterations, -I \n" " encrypt with the specified number of iterations when saving\n" +"\n" " --version\n" " --help\n" msgstr "" -#: src/pwmc.c:127 +#: src/pwmc.c:153 msgid "" "\n" "A url string (specified with --url) may be in the form of:\n" diff --git a/src/libpwmd.c b/src/libpwmd.c index 4fb7dca9..cd702cb9 100644 --- a/src/libpwmd.c +++ b/src/libpwmd.c @@ -1380,11 +1380,11 @@ gotpassword: if (pwm->tcp_conn && !local_pinentry) return rc; else if (local_pinentry) - rc = _getpin(pwm, &password, PINENTRY_OPEN_FAILED); + rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED); else #else if (local_pinentry) - rc = _getpin(pwm, &password, PINENTRY_OPEN_FAILED); + rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED); else #endif #else @@ -1953,3 +1953,13 @@ char *pwmd_strdup_printf(const char *fmt, ...) va_end(ap2); return buf; } + +gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result, + pwmd_pinentry_t which) +{ +#ifndef WITH_PINENTRY + return GPG_ERR_NOT_IMPLEMENTED; +#else + return _pwmd_getpin(pwm, filename, result, which); +#endif +} diff --git a/src/libpwmd.h.in b/src/libpwmd.h.in index b8626fb5..0b56d211 100644 --- a/src/libpwmd.h.in +++ b/src/libpwmd.h.in @@ -256,6 +256,26 @@ typedef enum { PWMD_SOCKET_SSH } pwmd_socket_t; + +/*! \typedef pwmd_pinentry_t + * + * For use with \ref pwmd_getpin(). + */ +typedef enum { + /*! When opening a file. */ + PWMD_PINENTRY_OPEN, + + /*! When opening a file failed. */ + PWMD_PINENTRY_OPEN_FAILED, + + /*! When saving a file. */ + PWMD_PINENTRY_SAVE, + + /*! For passphrase confirmation. */ + PWMD_PINENTRY_SAVE_CONFIRM +} pwmd_pinentry_t; + + /*! \typedef pwmd_passphrase_cb_t * * The value of the option \ref PWMD_OPTION_PASSPHRASE_CB which is set with @@ -660,6 +680,24 @@ gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...) __attribute__ ((warn_unused_result)); +/*! \brief Launch a local pinentry. + * + * Does not send any command to the server. + * + * \param pwm A handle. + * \param filename The filename to use in the pinentry dialog strings. + * \param[out] result The entered value in the pinentry dialog which should be + * freed with \ref pwmd_free(). + * \param which For setting the pinentry dialog strings. \ref pwmd_setopt() + * may also be used to override the defaults. + * + * \return 0 on success or an error. + */ +gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result, + pwmd_pinentry_t which) + __attribute__ ((warn_unused_result)); + + /*! \brief Open a file on the pwmd server. * * This will send the OPEN command to the server. diff --git a/src/pinentry.c b/src/pinentry.c index e1ebbe4b..4c544158 100644 --- a/src/pinentry.c +++ b/src/pinentry.c @@ -33,7 +33,7 @@ static pwm_t *gpwm; static int gelapsed, gtimeout; static gpg_error_t grc; -static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which); +static gpg_error_t set_pinentry_strings(pwm_t *pwm, pwmd_pinentry_t which); static void update_pinentry_settings(pwm_t *pwm) { @@ -226,7 +226,7 @@ static int quality_cb(void *data, const char *line) } #endif -static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which) +static gpg_error_t set_pinentry_strings(pwm_t *pwm, pwmd_pinentry_t which) { char *tmp, *desc = NULL; gpg_error_t rc; @@ -249,8 +249,8 @@ static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which) if (!pwm->prompt) goto fail_no_mem; - if (!pwm->desc && (which == PINENTRY_OPEN || which == PINENTRY_SAVE)) { - if (which == PINENTRY_OPEN) + if (!pwm->desc && (which == PWMD_PINENTRY_OPEN || which == PWMD_PINENTRY_SAVE)) { + if (which == PWMD_PINENTRY_OPEN) desc = pwmd_strdup_printf(N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below."), pwm->filename); else desc = pwmd_strdup_printf(N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."), pwm->filename); @@ -263,21 +263,24 @@ static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which) desc = pwm->desc; switch (which) { - case PINENTRY_OPEN: - case PINENTRY_SAVE: + case PWMD_PINENTRY_OPEN: + case PWMD_PINENTRY_SAVE: snprintf(tmp, ASSUAN_LINELENGTH+1, "SETERROR %s", desc); if (pwm->desc != desc) pwmd_free(desc); break; - case PINENTRY_OPEN_FAILED: + case PWMD_PINENTRY_OPEN_FAILED: snprintf(tmp, ASSUAN_LINELENGTH+1, "SETERROR %s", N_("Invalid passphrase, please try again.")); break; - case PINENTRY_SAVE_CONFIRM: + case PWMD_PINENTRY_SAVE_CONFIRM: snprintf(tmp, ASSUAN_LINELENGTH+1, "SETERROR %s", N_("Please type the passphrase again for confirmation.")); break; + default: + snprintf(tmp, ASSUAN_LINELENGTH+1, "SETERROR"); + break; } rc = pinentry_command(pwm, NULL, tmp); @@ -296,7 +299,7 @@ static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which) } #ifdef WITH_QUALITY - if (which == PINENTRY_SAVE) { + if (which == PWMD_PINENTRY_SAVE) { rc = pinentry_command(pwm, NULL, "SETQUALITYBAR"); if (rc) { @@ -379,7 +382,7 @@ static gpg_error_t do_getpin(pwm_t *pwm, char **result) return pinentry_command(pwm, result, "GETPIN"); } -gpg_error_t _getpin(pwm_t *pwm, char **result, int which) +gpg_error_t _getpin(pwm_t *pwm, char **result, pwmd_pinentry_t which) { grc = 0; gpg_error_t rc = set_pinentry_strings(pwm, which); @@ -417,7 +420,7 @@ gpg_error_t _do_save_getpin(pwm_t *pwm, char **password) char *result = NULL; again: - rc = _getpin(pwm, &result, confirm ? PINENTRY_SAVE_CONFIRM : PINENTRY_SAVE); + rc = _getpin(pwm, &result, confirm ? PWMD_PINENTRY_SAVE_CONFIRM : PWMD_PINENTRY_SAVE); if (rc) { _pinentry_disconnect(pwm); @@ -446,6 +449,30 @@ again: return 0; } +static gpg_error_t do_local_getpin(pwm_t *pwm, char **password, + pwmd_pinentry_t which) +{ + gpg_error_t rc; + + /* Another handle is using this pinentry method. Allowing this instance + * would reset the timeout and global handle which wouldn't be good. */ + if (gpwm) + return GPG_ERR_PIN_BLOCKED; + + if (pwm->pinentry_timeout != 0) { + gpwm = pwm; + gtimeout = abs(pwm->pinentry_timeout); + gelapsed = 0; + } + + rc = _getpin(pwm, password, which); + + /* Don't timeout when an invalid passphrase was entered. */ + gtimeout = 0; + gpwm = NULL; + return rc; +} + gpg_error_t _pinentry_open(pwm_t *pwm, const char *filename, char **password, int nb) { @@ -484,7 +511,7 @@ gpg_error_t _pinentry_open(pwm_t *pwm, const char *filename, char **password, } pw.error = _getpin(pwm, password, - !pwm->pin_try ? PINENTRY_OPEN : PINENTRY_OPEN_FAILED); + !pwm->pin_try ? PWMD_PINENTRY_OPEN : PWMD_PINENTRY_OPEN_FAILED); _pinentry_disconnect(pwm); if (gtimeout && gelapsed >= gtimeout) @@ -520,21 +547,18 @@ gpg_error_t _pinentry_open(pwm_t *pwm, const char *filename, char **password, return 0; } - /* Another handle is using this pinentry method. Allowing this instance - * would reset the timeout and global handle which wouldn't be good. */ - if (gpwm) - return GPG_ERR_PIN_BLOCKED; - - if (pwm->pinentry_timeout != 0) { - gpwm = pwm; - gtimeout = abs(pwm->pinentry_timeout); - gelapsed = 0; - } + return do_local_getpin(pwm, password, PWMD_PINENTRY_OPEN); +} - rc = _getpin(pwm, password, PINENTRY_OPEN); +gpg_error_t _pwmd_getpin(pwm_t *pwm, const char *filename, char **result, + pwmd_pinentry_t which) +{ + if (!pwm || !result) + return GPG_ERR_INV_ARG; - /* Don't timeout when an invalid passphrase was entered. */ - gtimeout = 0; - gpwm = NULL; + char *p = pwm->filename; + pwm->filename = (char *)filename; + gpg_error_t rc = do_local_getpin(pwm, result, which); + pwm->filename = p; return rc; } diff --git a/src/pinentry.h b/src/pinentry.h index 8fc5fd39..fbd107b5 100644 --- a/src/pinentry.h +++ b/src/pinentry.h @@ -24,7 +24,7 @@ void _pinentry_disconnect(pwm_t *pwm) __attribute__ ((visibility ("hidden"))); -gpg_error_t _getpin(pwm_t *pwm, char **result, int which) +gpg_error_t _getpin(pwm_t *pwm, char **result, pwmd_pinentry_t which) __attribute__ ((visibility ("hidden"))); gpg_error_t _do_save_getpin(pwm_t *pwm, char **password) @@ -34,4 +34,8 @@ gpg_error_t _pinentry_open(pwm_t *pwm, const char *filename, char **password, int nb) __attribute__ ((visibility ("hidden"))); +gpg_error_t _pwmd_getpin(pwm_t *pwm, const char *filename, char **result, + pwmd_pinentry_t which) + __attribute__ ((visibility ("hidden"))); + #endif diff --git a/src/pwmc.c b/src/pwmc.c index 695b1137..12bdfaed 100644 --- a/src/pwmc.c +++ b/src/pwmc.c @@ -70,9 +70,6 @@ static void usage(const char *pn, int status) "3=libpwmd async)\n" #endif "\n" - " --tries \n" - " number of pinentry tries before failing (3)\n" - "\n" #ifdef WITH_TCP " --host, -h \n" " connect to the specified hostname\n" @@ -102,9 +99,6 @@ static void usage(const char *pn, int status) " --url \n" " a url string to parse\n" "\n" - " --timeout \n" - " pinentry timeout\n" - "\n" " --no-status\n" " disable showing of status messages from the server\n" "\n" @@ -117,6 +111,12 @@ static void usage(const char *pn, int status) " --passphrase, -P \n" " passphrase to use (disables pinentry use)\n" "\n" + " --timeout \n" + " pinentry timeout\n" + "\n" + " --tries \n" + " number of pinentry tries before failing (3)\n" + "\n" " --pinentry \n" " the full path to the pinentry binary (server default)\n" "\n" @@ -135,6 +135,10 @@ static void usage(const char *pn, int status) " --lc-messages \n" " locale setting for pinentry\n" "\n" + + " --local-pinentry\n" + " force using a local pinentry\n" + "\n" " --output-fd \n" " redirect command output to the specified file descriptor\n" "\n" @@ -144,6 +148,9 @@ static void usage(const char *pn, int status) " --save, -S\n" " send the SAVE command before exiting\n" "\n" + " --force-save\n" + " force asking for a passphrase when saving\n" + "\n" " --iterations, -I \n" " encrypt with the specified number of iterations when saving\n" "\n" @@ -284,6 +291,8 @@ int main(int argc, char *argv[]) long iter = -2; int have_iter = 0; int timeout = 0; + int local_pin = 0; + int force_save = 0; #ifdef WITH_TCP char *host = NULL; int port = DEFAULT_PORT; @@ -294,6 +303,8 @@ int main(int argc, char *argv[]) int prot = PWMD_IP_ANY; #endif int tries = 0; + int local_tries = 3; + int try = 0; #ifdef DEBUG int method = 0; fd_set rfds; @@ -308,10 +319,11 @@ int main(int argc, char *argv[]) OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER, OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6, #endif - OPT_URL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE, - OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_PASSPHRASE, - OPT_SOCKET, OPT_SAVE, OPT_ITERATIONS, OPT_OUTPUT_FD, OPT_INQUIRE_FD, - OPT_NO_STATUS, OPT_NAME, OPT_VERSION, OPT_HELP, + OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE, + OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, + OPT_PINENTRY, OPT_PASSPHRASE, OPT_SOCKET, OPT_SAVE, OPT_ITERATIONS, + OPT_OUTPUT_FD, OPT_INQUIRE_FD, OPT_NO_STATUS, OPT_NAME, OPT_VERSION, + OPT_HELP, }; const struct option long_opts[] = { #ifdef DEBUG @@ -328,6 +340,8 @@ int main(int argc, char *argv[]) { "ipv6", 0, 0, '6' }, #endif { "url", 1, 0, 0 }, + { "local-pinentry", 0, 0 }, + { "force-save", 0, 0 }, { "ttyname", 1, 0, 'y' }, { "ttytype", 1, 0, 't' }, { "display", 1, 0, 'd' }, @@ -376,6 +390,12 @@ int main(int argc, char *argv[]) case OPT_URL: url_string = optarg; break; + case OPT_LOCAL: + local_pin = 1; + break; + case OPT_FORCE_SAVE: + force_save = 1; + break; case OPT_LC_CTYPE: lcctype = pwmd_strdup(optarg); break; @@ -387,6 +407,7 @@ int main(int argc, char *argv[]) break; case OPT_TRIES: tries = atoi(optarg); + local_tries = tries; break; case OPT_SOCKET: socketpath = pwmd_strdup(optarg); @@ -624,6 +645,29 @@ int main(int argc, char *argv[]) goto done; } + if (local_pin && filename) { +local_password: + if (try++ == local_tries) + goto done; + + if (password) + pwmd_free(password); + + password = NULL; + + if (try > 1) + error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0); + + error = pwmd_getpin(pwm, filename, &password, + try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN); + + if (error) + goto done; + + if (try == 1) + goto do_open; + } + if (password) { error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password); @@ -689,6 +733,7 @@ int main(int argc, char *argv[]) goto done; } +do_open: if (filename) { #ifdef DEBUG switch (method) { @@ -707,6 +752,9 @@ int main(int argc, char *argv[]) break; } + if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE) + goto local_password; + if (error) goto done; @@ -806,8 +854,9 @@ int main(int argc, char *argv[]) done: memset(command, 0, sizeof(command)); pwmd_free(password); + password = NULL; - if (!error && save) { + if (!error && save && filename) { if (iter != -2) { error = pwmd_command(pwm, &result, "OPTION ITERATIONS=%i", iter); @@ -815,7 +864,58 @@ done: goto done; } + if (force_save) { + error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename); + + if (error) + goto done; + + error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL); + + if (error) + goto done; + } + + if (local_pin) { + char *p1; +again: + if (!force_save) { + error = pwmd_command(pwm, NULL, "ISCACHED %s", filename); + + if (error && error != GPG_ERR_NOT_FOUND && + error != GPG_ERR_ENOENT) + goto done; + else if (!error) + goto do_save; + } + + error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE); + + if (error) + goto done; + + error = pwmd_getpin(pwm, filename, &password, + PWMD_PINENTRY_SAVE_CONFIRM); + + if (error) + goto done; + + if (strcmp(p1, password)) { + pwmd_free(p1); + pwmd_free(password); + password = NULL; + goto again; + } + + error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password); + pwmd_free(password); + + if (error) + goto done; + } + #ifdef DEBUG +do_save: switch (method) { case 0: error = pwmd_save(pwm); diff --git a/src/types.h b/src/types.h index 165e6c62..97ddb1bc 100644 --- a/src/types.h +++ b/src/types.h @@ -62,13 +62,6 @@ typedef enum { ASYNC_CMD_SAVE2, } pwmd_async_cmd_t; -enum { - PINENTRY_OPEN, - PINENTRY_OPEN_FAILED, - PINENTRY_SAVE, - PINENTRY_SAVE_CONFIRM -}; - #ifdef WITH_TCP typedef struct { char *host; -- 2.11.4.GIT