/* preset-passphrase.c - A tool to preset a passphrase. * Copyright (C) 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_LANGINFO_CODESET #include #endif #ifdef HAVE_DOSISH_SYSTEM #include /* for setmode() */ #endif #ifdef HAVE_W32_SYSTEM #include /* To initialize the sockets. fixme */ #endif #define JNLIB_NEED_LOG_LOGV #include "agent.h" #include "minip12.h" #include "simple-pwquery.h" #include "i18n.h" #include "sysutils.h" enum cmd_and_opt_values { aNull = 0, oVerbose = 'v', oPassphrase = 'P', oPreset = 'c', oForget = 'f', oNoVerbose = 500, oHomedir, aTest }; static const char *opt_homedir; static const char *opt_passphrase; static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, N_("@Options:\n ") }, { oVerbose, "verbose", 0, "verbose" }, { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, { oPreset, "preset", 256, "preset passphrase"}, { oForget, "forget", 256, "forget passphrase"}, { oHomedir, "homedir", 2, "@" }, {0} }; static const char * my_strusage (int level) { const char *p; switch (level) { case 11: p = "gpg-preset-passphrase (GnuPG)"; break; case 13: p = VERSION; break; case 17: p = PRINTABLE_OS_NAME; break; case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n"); break; case 1: case 40: p = _("Usage: gpg-preset-passphrase [options] KEYGRIP (-h for help)\n"); break; case 41: p = _("Syntax: gpg-preset-passphrase [options] KEYGRIP\n" "Password cache maintenance\n"); break; default: p = NULL; } return p; } static void i18n_init (void) { #ifdef USE_SIMPLE_GETTEXT set_gettext_file( PACKAGE_GT ); #else #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain (PACKAGE_GT, LOCALEDIR); textdomain (PACKAGE_GT); #endif #endif } static gpg_error_t map_spwq_error (int err) { switch (err) { case 0: return 0; case SPWQ_OUT_OF_CORE: return gpg_error_from_errno (ENOMEM); case SPWQ_IO_ERROR: return gpg_error_from_errno (EIO); case SPWQ_PROTOCOL_ERROR: return gpg_error (GPG_ERR_PROTOCOL_VIOLATION); case SPWQ_ERR_RESPONSE: return gpg_error (GPG_ERR_INV_RESPONSE); case SPWQ_NO_AGENT: return gpg_error (GPG_ERR_NO_AGENT); case SPWQ_SYS_ERROR: return gpg_error_from_errno (errno); case SPWQ_GENERAL_ERROR: default: return gpg_error (GPG_ERR_GENERAL); } } /* Convert the string SRC into HEX encoding. Caller needs to xfree the returned string. */ static char * make_hexstring (const char *src) { int len = 2 * strlen (src) + 1; char *dst; char *res; res = dst = xtrymalloc (len); if (!dst) { log_error ("can not escape string: %s\n", gpg_strerror (gpg_error_from_errno (errno))); return NULL; } #define _tohex(nr) ((nr) < 10 ? ((nr) + '0') : (((nr) - 10) + 'A')) #define tohex1(p) _tohex (*((unsigned char *) p) & 15) #define tohex2(p) _tohex ((*((unsigned char *) p) >> 4) & 15) while (*src) { *(dst++) = tohex2 (src); *(dst++) = tohex1 (src); src++; } *dst = '\0'; return res; } static void preset_passphrase (const char *keygrip) { int rc; char *line; /* FIXME: Use secure memory. */ char passphrase[500]; char *passphrase_esc; if (!opt_passphrase) { rc = read (0, passphrase, sizeof (passphrase) - 1); if (rc < 0) { log_error ("reading passphrase failed: %s\n", gpg_strerror (gpg_error_from_errno (errno))); return; } passphrase[rc] = '\0'; line = strchr (passphrase, '\n'); if (line) { if (line > passphrase && line[-1] == '\r') line--; *line = '\0'; } /* FIXME: How to handle empty passwords? */ } passphrase_esc = make_hexstring (opt_passphrase ? opt_passphrase : passphrase); if (!passphrase_esc) { /* Error message printed by callee. */ return; } rc = asprintf (&line, "PRESET_PASSPHRASE %s -1 %s\n", keygrip, passphrase_esc); wipememory (passphrase_esc, strlen (passphrase_esc)); xfree (passphrase_esc); if (rc < 0) { log_error ("caching passphrase failed: %s\n", gpg_strerror (gpg_error_from_errno (errno))); return; } if (!opt_passphrase) wipememory (passphrase, sizeof (passphrase)); rc = map_spwq_error (simple_query (line)); if (rc) { log_error ("caching passphrase failed: %s\n", gpg_strerror (rc)); return; } wipememory (line, strlen (line)); free (line); } static void forget_passphrase (const char *keygrip) { int rc; char *line; rc = asprintf (&line, "CLEAR_PASSPHRASE %s\n", keygrip); if (rc < 0) { log_error ("clearing passphrase failed: %s\n", gpg_strerror (gpg_error_from_errno (errno))); return; } free (line); } int main (int argc, char **argv) { ARGPARSE_ARGS pargs; int cmd = 0; const char *keygrip = NULL; set_strusage (my_strusage); log_set_prefix ("gpg-preset-passphrase", 1); /* Try to auto set the character set. */ set_native_charset (NULL); #ifdef HAVE_W32_SYSTEM /* Fixme: Need to initialize the Windows sockets: This should be moved to another place and we should make sure that it won't get done twice, like when Pth is used too. */ { WSADATA wsadat; if (WSAStartup (0x202, &wsadat) ) { log_error ("error initializing socket library: ec=%d\n", (int)WSAGetLastError () ); return 2; } } #endif i18n_init (); opt_homedir = default_homedir (); pargs.argc = &argc; pargs.argv = &argv; pargs.flags= 1; /* (do not remove the args) */ while (arg_parse (&pargs, opts) ) { switch (pargs.r_opt) { case oVerbose: opt.verbose++; break; case oHomedir: opt_homedir = pargs.r.ret_str; break; case oPreset: cmd = oPreset; break; case oForget: cmd = oForget; break; case oPassphrase: opt_passphrase = pargs.r.ret_str; break; default : pargs.err = 2; break; } } if (log_get_errorcount(0)) exit(2); if (argc == 1) keygrip = *argv; else usage (1); if (cmd == oPreset) preset_passphrase (keygrip); else if (cmd == oForget) forget_passphrase (keygrip); else log_error ("one of the options --preset or --forget must be given\n"); agent_exit (0); return 8; /*NOTREACHED*/ } void agent_exit (int rc) { rc = rc? rc : log_get_errorcount(0)? 2 : 0; exit (rc); }