1 /* Fake pinentry program for the OpenPGP test suite.
3 * Copyright (C) 2016 g10 code GmbH
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
28 static FILE *log_stream;
32 reply (const char *fmt, ...)
39 fprintf (log_stream, "> ");
41 vfprintf (log_stream, fmt, ap);
45 result = vprintf (fmt, ap);
53 /* Return the first line from FNAME, removing it from the file. */
55 get_passphrase (const char *fname)
57 char *passphrase = NULL;
63 fname_len = strlen (fname);
64 fname_new = malloc (fname_len + 5);
65 if (fname_new == NULL)
70 snprintf (fname_new, fname_len + 5, "%s.new", fname);
72 source = fopen (fname, "r");
79 sink = fopen (fname_new, "w");
86 while (fgets (linebuf, sizeof linebuf, source))
88 linebuf[sizeof linebuf - 1] = 0;
89 if (passphrase == NULL)
91 passphrase = strdup (linebuf);
92 if (passphrase == NULL)
99 fputs (linebuf, sink);
118 fprintf (stderr, "Failed to remove %s: %s",
119 fname, strerror (errno));
123 if (rename (fname_new, fname))
125 fprintf (stderr, "Failed to rename %s to %s: %s",
126 fname, fname_new, strerror (errno));
133 #define whitespacep(p) (*(p) == ' ' || *(p) == '\t' \
134 || *(p) == '\r' || *(p) == '\n')
138 rstrip (char *buffer)
142 return; /* This is to avoid p = buffer - 1 */
143 for (p = buffer + strlen (buffer) - 1; p >= buffer; p--)
145 if (! whitespacep (p))
152 /* Skip over options in LINE.
154 Blanks after the options are also removed. Options are indicated
155 by two leading dashes followed by a string consisting of non-space
156 characters. The special option "--" indicates an explicit end of
157 options; all what follows will not be considered an option. The
158 first no-option string also indicates the end of option parsing. */
160 skip_options (const char *line)
162 while (whitespacep (line))
164 while (*line == '-' && line[1] == '-')
166 while (*line && !whitespacep (line))
168 while (whitespacep (line))
175 /* Return a pointer to the argument of the option with NAME. If such
176 an option is not given, NULL is returned. */
178 option_value (const char *line, const char *name)
181 int n = strlen (name);
183 s = strstr (line, name);
184 if (s && s >= skip_options (line))
186 if (s && (s == line || whitespacep (s-1))
187 && s[n] && (whitespacep (s+n) || s[n] == '='))
190 s += strspn (s, " ");
191 if (*s && !whitespacep(s))
198 main (int argc, char **argv)
201 char *option_user_data = NULL;
202 int got_environment_user_data;
204 char *passphrasefile;
207 /* We get our options via PINENTRY_USER_DATA. */
208 (void) argc, (void) argv;
210 setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
211 setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
213 args = getenv ("PINENTRY_USER_DATA");
214 got_environment_user_data = !!args;
219 logfile = option_value (args, "--logfile");
222 char *p = logfile, more;
223 while (*p && ! whitespacep (p))
227 args = more ? p+1 : p;
229 log_stream = fopen (logfile, "a");
237 passphrasefile = option_value (args, "--passphrasefile");
240 char *p = passphrasefile, more;
241 while (*p && ! whitespacep (p))
245 args = more ? p+1 : p;
247 passphrase = get_passphrase (passphrasefile);
250 reply ("# Passphrasefile '%s' is empty. Terminating.\n",
259 passphrase = skip_options (args);
260 if (*passphrase == 0)
261 passphrase = "no PINENTRY_USER_DATA -- using default passphrase";
264 reply ("# fake-pinentry(%u) started. Passphrase='%s'.\n",
265 (unsigned int)getpid (), passphrase);
266 reply ("OK - what's up?\n");
268 while (! feof (stdin))
272 if (fgets (buffer, sizeof buffer, stdin) == NULL)
276 fprintf (log_stream, "< %s", buffer);
280 #define OPT_USER_DATA "OPTION pinentry-user-data="
282 if (strncmp (buffer, "GETPIN", 6) == 0)
283 reply ("D %s\n", passphrase);
284 else if (strncmp (buffer, "BYE", 3) == 0)
289 else if (strncmp (buffer, OPT_USER_DATA, strlen (OPT_USER_DATA)) == 0)
291 if (got_environment_user_data)
293 reply ("OK - I already got the data from the environment.\n");
300 free (option_user_data);
301 option_user_data = args = strdup (buffer + strlen (OPT_USER_DATA));
310 reply ("# Connection terminated.\n");
314 free (option_user_data);