Line data Source code
1 : /* Fake pinentry program for the OpenPGP test suite.
2 : *
3 : * Copyright (C) 2016 g10 code GmbH
4 : *
5 : * This file is part of GnuPG.
6 : *
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.
11 : *
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.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <stdlib.h>
22 : #include <stdio.h>
23 : #include <string.h>
24 : #include <stdarg.h>
25 :
26 : FILE *log_stream;
27 :
28 : int
29 223 : reply (const char *fmt, ...)
30 : {
31 : int result;
32 : va_list ap;
33 :
34 223 : if (log_stream)
35 : {
36 23 : fprintf (log_stream, "> ");
37 23 : va_start (ap, fmt);
38 23 : vfprintf (log_stream, fmt, ap);
39 23 : va_end (ap);
40 : }
41 223 : va_start (ap, fmt);
42 223 : result = vprintf (fmt, ap);
43 223 : va_end (ap);
44 :
45 223 : return result;
46 : }
47 :
48 : /* Return the first line from FNAME, removing it from the file. */
49 : char *
50 1 : get_passphrase (const char *fname)
51 : {
52 1 : char *passphrase = NULL;
53 : size_t fname_len;
54 : char *fname_new;
55 : FILE *source, *sink;
56 : char linebuf[80];
57 :
58 1 : fname_len = strlen (fname);
59 1 : fname_new = malloc (fname_len + 5);
60 1 : if (fname_new == NULL)
61 : {
62 0 : perror ("malloc");
63 0 : exit (1);
64 : }
65 1 : snprintf (fname_new, fname_len + 5, "%s.new", fname);
66 :
67 1 : source = fopen (fname, "r");
68 1 : if (! source)
69 : {
70 0 : perror (fname);
71 0 : exit (1);
72 : }
73 :
74 1 : sink = fopen (fname_new, "w");
75 1 : if (! sink)
76 : {
77 0 : perror (fname_new);
78 0 : exit (1);
79 : }
80 :
81 3 : while (fgets (linebuf, sizeof linebuf, source))
82 : {
83 1 : linebuf[sizeof linebuf - 1] = 0;
84 1 : if (passphrase == NULL)
85 : {
86 1 : passphrase = strdup (linebuf);
87 1 : if (passphrase == NULL)
88 : {
89 0 : perror ("strdup");
90 0 : exit (1);
91 : }
92 : }
93 : else
94 0 : fputs (linebuf, sink);
95 : }
96 :
97 1 : if (ferror (source))
98 : {
99 0 : perror (fname);
100 0 : exit (1);
101 : }
102 :
103 1 : if (ferror (sink))
104 : {
105 0 : perror (fname_new);
106 0 : exit (1);
107 : }
108 :
109 1 : fclose (source);
110 1 : fclose (sink);
111 1 : rename (fname_new, fname);
112 1 : return passphrase;
113 : }
114 :
115 :
116 : #define spacep(p) (*(p) == ' ' || *(p) == '\t')
117 :
118 : /* Skip over options in LINE.
119 :
120 : Blanks after the options are also removed. Options are indicated
121 : by two leading dashes followed by a string consisting of non-space
122 : characters. The special option "--" indicates an explicit end of
123 : options; all what follows will not be considered an option. The
124 : first no-option string also indicates the end of option parsing. */
125 : char *
126 10 : skip_options (const char *line)
127 : {
128 20 : while (spacep (line))
129 0 : line++;
130 23 : while (*line == '-' && line[1] == '-')
131 : {
132 126 : while (*line && !spacep (line))
133 120 : line++;
134 7 : while (spacep (line))
135 1 : line++;
136 : }
137 10 : return (char*) line;
138 : }
139 :
140 :
141 : /* Return a pointer to the argument of the option with NAME. If such
142 : an option is not given, NULL is returned. */
143 : char *
144 18 : option_value (const char *line, const char *name)
145 : {
146 : char *s;
147 18 : int n = strlen (name);
148 :
149 18 : s = strstr (line, name);
150 18 : if (s && s >= skip_options (line))
151 0 : return NULL;
152 18 : if (s && (s == line || spacep (s-1))
153 2 : && s[n] && (spacep (s+n) || s[n] == '='))
154 : {
155 2 : s += n + 1;
156 2 : s += strspn (s, " ");
157 2 : if (*s && !spacep(s))
158 2 : return s;
159 : }
160 16 : return NULL;
161 : }
162 :
163 : int
164 9 : main (int argc, char **argv)
165 : {
166 : char *args;
167 : char *logfile;
168 : char *passphrasefile;
169 : char *passphrase;
170 :
171 : /* We get our options via PINENTRY_USER_DATA. */
172 : (void) argc, (void) argv;
173 :
174 9 : setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
175 9 : setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
176 :
177 9 : args = getenv ("PINENTRY_USER_DATA");
178 9 : if (! args)
179 8 : args = "";
180 :
181 9 : logfile = option_value (args, "--logfile");
182 9 : if (logfile)
183 : {
184 1 : char *p = logfile, more;
185 28 : while (*p && ! spacep (p))
186 26 : p++;
187 1 : more = !! *p;
188 1 : *p = 0;
189 1 : args = more ? p+1 : p;
190 :
191 1 : log_stream = fopen (logfile, "a");
192 1 : if (! log_stream)
193 : {
194 0 : perror (logfile);
195 0 : return 1;
196 : }
197 : }
198 :
199 9 : passphrasefile = option_value (args, "--passphrasefile");
200 9 : if (passphrasefile)
201 : {
202 1 : char *p = passphrasefile, more;
203 27 : while (*p && ! spacep (p))
204 25 : p++;
205 1 : more = !! *p;
206 1 : *p = 0;
207 1 : args = more ? p+1 : p;
208 :
209 1 : passphrase = get_passphrase (passphrasefile);
210 1 : if (! passphrase)
211 : {
212 0 : reply ("# Passphrasefile '%s' is empty. Terminating.\n",
213 : passphrasefile);
214 0 : return 1;
215 : }
216 :
217 1 : p = passphrase + strlen (passphrase) - 1;
218 1 : if (*p == '\n')
219 1 : *p = 0;
220 : }
221 : else
222 : {
223 8 : passphrase = skip_options (args);
224 8 : if (*passphrase == 0)
225 8 : passphrase = "no PINENTRY_USER_DATA -- using default passphrase";
226 : }
227 :
228 9 : reply ("# fake-pinentry started. Passphrase='%s'.\n", passphrase);
229 9 : reply ("OK - what's up?\n");
230 :
231 9 : while (! feof (stdin))
232 : {
233 : char buffer[1024];
234 :
235 187 : if (fgets (buffer, sizeof buffer, stdin) == NULL)
236 9 : break;
237 :
238 187 : if (log_stream)
239 19 : fprintf (log_stream, "< %s", buffer);
240 :
241 187 : if (strncmp (buffer, "GETPIN", 6) == 0)
242 9 : reply ("D %s\n", passphrase);
243 178 : else if (strncmp (buffer, "BYE", 3) == 0)
244 : {
245 9 : reply ("OK\n");
246 9 : break;
247 : }
248 :
249 178 : reply ("OK\n");
250 : }
251 :
252 9 : reply ("# Connection terminated.\n");
253 9 : if (log_stream)
254 1 : fclose (log_stream);
255 :
256 9 : return 0;
257 : }
|