Line data Source code
1 : /* simple-pwquery.c - A simple password query client for gpg-agent
2 : * Copyright (C) 2002, 2004, 2007 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : /* This module is intended as a standalone client implementation to
21 : gpg-agent's GET_PASSPHRASE command. In particular it does not use
22 : the Assuan library and can only cope with an already running
23 : gpg-agent. Some stuff is configurable in the header file. */
24 :
25 : #ifdef HAVE_CONFIG_H
26 : #include <config.h>
27 : #endif
28 : #include <stdlib.h>
29 : #include <stddef.h>
30 : #include <string.h>
31 : #include <errno.h>
32 : #include <unistd.h>
33 : #ifdef HAVE_W32_SYSTEM
34 : #include <winsock2.h>
35 : #else
36 : #include <sys/socket.h>
37 : #include <sys/un.h>
38 : #endif
39 : #ifdef HAVE_LOCALE_H
40 : #include <locale.h>
41 : #endif
42 :
43 : #define GNUPG_COMMON_NEED_AFLOCAL
44 : #include "../common/mischelp.h"
45 : #ifdef HAVE_W32_SYSTEM
46 : #include "../common/w32-afunix.h"
47 : #endif
48 :
49 :
50 : #define SIMPLE_PWQUERY_IMPLEMENTATION 1
51 : #include "simple-pwquery.h"
52 :
53 : #ifndef _
54 : #define _(a) (a)
55 : #endif
56 :
57 : #if !defined (hexdigitp) && !defined (xtoi_2)
58 : #define digitp(p) (*(p) >= '0' && *(p) <= '9')
59 : #define hexdigitp(a) (digitp (a) \
60 : || (*(a) >= 'A' && *(a) <= 'F') \
61 : || (*(a) >= 'a' && *(a) <= 'f'))
62 : #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
63 : *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
64 : #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
65 : #endif
66 :
67 :
68 : /* Name of the socket to be used. This is a kludge to keep on using
69 : the existsing code despite that we only support a standard socket. */
70 : static char *default_gpg_agent_info;
71 :
72 :
73 :
74 :
75 :
76 : #ifndef HAVE_STPCPY
77 : static char *
78 : my_stpcpy(char *a,const char *b)
79 : {
80 : while( *b )
81 : *a++ = *b++;
82 : *a = 0;
83 :
84 : return (char*)a;
85 : }
86 : #define stpcpy(a,b) my_stpcpy((a), (b))
87 : #endif
88 :
89 :
90 :
91 : /* Write NBYTES of BUF to file descriptor FD. */
92 : static int
93 60 : writen (int fd, const void *buf, size_t nbytes)
94 : {
95 60 : size_t nleft = nbytes;
96 : int nwritten;
97 :
98 180 : while (nleft > 0)
99 : {
100 : #ifdef HAVE_W32_SYSTEM
101 : nwritten = send (fd, buf, nleft, 0);
102 : #else
103 60 : nwritten = write (fd, buf, nleft);
104 : #endif
105 60 : if (nwritten < 0)
106 : {
107 0 : if (errno == EINTR)
108 0 : nwritten = 0;
109 : else {
110 : #ifdef SPWQ_USE_LOGGING
111 0 : log_error ("write failed: %s\n", strerror (errno));
112 : #endif
113 0 : return SPWQ_IO_ERROR;
114 : }
115 : }
116 60 : nleft -= nwritten;
117 60 : buf = (const char*)buf + nwritten;
118 : }
119 :
120 60 : return 0;
121 : }
122 :
123 :
124 : /* Read an entire line and return number of bytes read. */
125 : static int
126 70 : readline (int fd, char *buf, size_t buflen)
127 : {
128 70 : size_t nleft = buflen;
129 : char *p;
130 70 : int nread = 0;
131 :
132 140 : while (nleft > 0)
133 : {
134 : #ifdef HAVE_W32_SYSTEM
135 : int n = recv (fd, buf, nleft, 0);
136 : #else
137 70 : int n = read (fd, buf, nleft);
138 : #endif
139 70 : if (n < 0)
140 : {
141 0 : if (errno == EINTR)
142 0 : continue;
143 0 : return -(SPWQ_IO_ERROR);
144 : }
145 70 : else if (!n)
146 : {
147 0 : return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
148 : }
149 70 : p = buf;
150 70 : nleft -= n;
151 70 : buf += n;
152 70 : nread += n;
153 :
154 70 : for (; n && *p != '\n'; n--, p++)
155 : ;
156 70 : if (n)
157 : {
158 70 : break; /* At least one full line available - that's enough.
159 : This function is just a simple implementation, so
160 : it is okay to forget about pending bytes. */
161 : }
162 : }
163 :
164 70 : return nread;
165 : }
166 :
167 :
168 : /* Send an option to the agent */
169 : static int
170 50 : agent_send_option (int fd, const char *name, const char *value)
171 : {
172 : char buf[200];
173 : int nread;
174 : char *line;
175 : int i;
176 :
177 50 : line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
178 50 : if (!line)
179 0 : return SPWQ_OUT_OF_CORE;
180 50 : strcpy (stpcpy (stpcpy (stpcpy (
181 50 : stpcpy (line, "OPTION "), name), "="), value), "\n");
182 50 : i = writen (fd, line, strlen (line));
183 50 : spwq_free (line);
184 50 : if (i)
185 0 : return i;
186 :
187 : /* get response */
188 50 : nread = readline (fd, buf, DIM(buf)-1);
189 50 : if (nread < 0)
190 0 : return -nread;
191 50 : if (nread < 3)
192 0 : return SPWQ_PROTOCOL_ERROR;
193 :
194 50 : if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
195 50 : return 0; /* okay */
196 :
197 0 : return SPWQ_ERR_RESPONSE;
198 : }
199 :
200 :
201 : /* Send all available options to the agent. */
202 : static int
203 10 : agent_send_all_options (int fd)
204 : {
205 10 : char *dft_display = NULL;
206 10 : char *dft_ttyname = NULL;
207 10 : char *dft_ttytype = NULL;
208 10 : char *dft_xauthority = NULL;
209 10 : char *dft_pinentry_user_data = NULL;
210 10 : int rc = 0;
211 :
212 10 : dft_display = getenv ("DISPLAY");
213 10 : if (dft_display)
214 : {
215 10 : if ((rc = agent_send_option (fd, "display", dft_display)))
216 0 : return rc;
217 : }
218 :
219 10 : dft_ttyname = getenv ("GPG_TTY");
220 : #if !defined(HAVE_W32_SYSTEM) && !defined(HAVE_BROKEN_TTYNAME)
221 10 : if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
222 10 : dft_ttyname = ttyname (0);
223 : #endif
224 10 : if (dft_ttyname && *dft_ttyname)
225 : {
226 10 : if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
227 0 : return rc;
228 : }
229 :
230 10 : dft_ttytype = getenv ("TERM");
231 10 : if (dft_ttyname && dft_ttytype)
232 : {
233 10 : if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
234 0 : return rc;
235 : }
236 :
237 : #if defined(HAVE_SETLOCALE)
238 : {
239 10 : char *old_lc = NULL;
240 10 : char *dft_lc = NULL;
241 :
242 : #if defined(LC_CTYPE)
243 10 : old_lc = setlocale (LC_CTYPE, NULL);
244 10 : if (old_lc)
245 : {
246 10 : char *p = spwq_malloc (strlen (old_lc)+1);
247 10 : if (!p)
248 0 : return SPWQ_OUT_OF_CORE;
249 10 : strcpy (p, old_lc);
250 10 : old_lc = p;
251 : }
252 10 : dft_lc = setlocale (LC_CTYPE, "");
253 10 : if (dft_ttyname && dft_lc)
254 10 : rc = agent_send_option (fd, "lc-ctype", dft_lc);
255 10 : if (old_lc)
256 : {
257 10 : setlocale (LC_CTYPE, old_lc);
258 10 : spwq_free (old_lc);
259 : }
260 10 : if (rc)
261 0 : return rc;
262 : #endif
263 :
264 : #if defined(LC_MESSAGES)
265 10 : old_lc = setlocale (LC_MESSAGES, NULL);
266 10 : if (old_lc)
267 : {
268 10 : char *p = spwq_malloc (strlen (old_lc)+1);
269 10 : if (!p)
270 0 : return SPWQ_OUT_OF_CORE;
271 10 : strcpy (p, old_lc);
272 10 : old_lc = p;
273 : }
274 10 : dft_lc = setlocale (LC_MESSAGES, "");
275 10 : if (dft_ttyname && dft_lc)
276 10 : rc = agent_send_option (fd, "lc-messages", dft_lc);
277 10 : if (old_lc)
278 : {
279 10 : setlocale (LC_MESSAGES, old_lc);
280 10 : spwq_free (old_lc);
281 : }
282 10 : if (rc)
283 0 : return rc;
284 : #endif
285 : }
286 : #endif /*HAVE_SETLOCALE*/
287 :
288 : /* Send the XAUTHORITY variable. */
289 10 : dft_xauthority = getenv ("XAUTHORITY");
290 10 : if (dft_xauthority)
291 : {
292 : /* We ignore errors here because older gpg-agents don't support
293 : this option. */
294 0 : agent_send_option (fd, "xauthority", dft_xauthority);
295 : }
296 :
297 : /* Send the PINENTRY_USER_DATA variable. */
298 10 : dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
299 10 : if (dft_pinentry_user_data)
300 : {
301 : /* We ignore errors here because older gpg-agents don't support
302 : this option. */
303 0 : agent_send_option (fd, "pinentry-user-data", dft_pinentry_user_data);
304 : }
305 :
306 10 : return 0;
307 : }
308 :
309 :
310 :
311 : /* Try to open a connection to the agent, send all options and return
312 : the file descriptor for the connection. Return -1 in case of
313 : error. */
314 : static int
315 10 : agent_open (int *rfd)
316 : {
317 : int rc;
318 : int fd;
319 : char *infostr, *p;
320 : struct sockaddr_un client_addr;
321 : size_t len;
322 : char line[200];
323 : int nread;
324 :
325 10 : *rfd = -1;
326 10 : infostr = default_gpg_agent_info;
327 10 : if ( !infostr || !*infostr )
328 : {
329 : #ifdef SPWQ_USE_LOGGING
330 0 : log_error (_("no gpg-agent running in this session\n"));
331 : #endif
332 0 : return SPWQ_NO_AGENT;
333 : }
334 10 : p = spwq_malloc (strlen (infostr)+1);
335 10 : if (!p)
336 0 : return SPWQ_OUT_OF_CORE;
337 10 : strcpy (p, infostr);
338 10 : infostr = p;
339 :
340 10 : if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
341 10 : || (p-infostr)+1 >= sizeof client_addr.sun_path )
342 : {
343 0 : return SPWQ_NO_AGENT;
344 : }
345 10 : *p++ = 0;
346 :
347 30 : while (*p && *p != PATHSEP_C)
348 10 : p++;
349 :
350 : #ifdef HAVE_W32_SYSTEM
351 : fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
352 : #else
353 10 : fd = socket (AF_UNIX, SOCK_STREAM, 0);
354 : #endif
355 10 : if (fd == -1)
356 : {
357 : #ifdef SPWQ_USE_LOGGING
358 0 : log_error ("can't create socket: %s\n", strerror(errno) );
359 : #endif
360 0 : return SPWQ_SYS_ERROR;
361 : }
362 :
363 10 : memset (&client_addr, 0, sizeof client_addr);
364 10 : client_addr.sun_family = AF_UNIX;
365 10 : strcpy (client_addr.sun_path, infostr);
366 10 : len = SUN_LEN (&client_addr);
367 :
368 : #ifdef HAVE_W32_SYSTEM
369 : rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
370 : #else
371 10 : rc = connect (fd, (struct sockaddr*)&client_addr, len );
372 : #endif
373 10 : if (rc == -1)
374 : {
375 : #ifdef SPWQ_USE_LOGGING
376 0 : log_error ( _("can't connect to '%s': %s\n"), infostr, strerror (errno));
377 : #endif
378 0 : close (fd );
379 0 : return SPWQ_IO_ERROR;
380 : }
381 :
382 10 : nread = readline (fd, line, DIM(line));
383 20 : if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
384 20 : && (line[2] == '\n' || line[2] == ' ')) )
385 : {
386 : #ifdef SPWQ_USE_LOGGING
387 0 : log_error ( _("communication problem with gpg-agent\n"));
388 : #endif
389 0 : close (fd );
390 0 : return SPWQ_PROTOCOL_ERROR;
391 : }
392 :
393 10 : rc = agent_send_all_options (fd);
394 10 : if (rc)
395 : {
396 : #ifdef SPWQ_USE_LOGGING
397 0 : log_error (_("problem setting the gpg-agent options\n"));
398 : #endif
399 0 : close (fd);
400 0 : return rc;
401 : }
402 :
403 10 : *rfd = fd;
404 10 : return 0;
405 : }
406 :
407 :
408 : /* Copy text to BUFFER and escape as required. Return a pointer to
409 : the end of the new buffer. Note that BUFFER must be large enough
410 : to keep the entire text; allocataing it 3 times the size of TEXT
411 : is sufficient. */
412 : static char *
413 0 : copy_and_escape (char *buffer, const char *text)
414 : {
415 : int i;
416 0 : const unsigned char *s = (unsigned char *)text;
417 0 : char *p = buffer;
418 :
419 :
420 0 : for (i=0; s[i]; i++)
421 : {
422 0 : if (s[i] < ' ' || s[i] == '+')
423 : {
424 0 : sprintf (p, "%%%02X", s[i]);
425 0 : p += 3;
426 : }
427 0 : else if (s[i] == ' ')
428 0 : *p++ = '+';
429 : else
430 0 : *p++ = s[i];
431 : }
432 0 : return p;
433 : }
434 :
435 :
436 : /* Set the name of the default socket to NAME. */
437 : int
438 10 : simple_pw_set_socket (const char *name)
439 : {
440 10 : spwq_free (default_gpg_agent_info);
441 10 : if (name)
442 : {
443 10 : default_gpg_agent_info = spwq_malloc (strlen (name) + 4 + 1);
444 10 : if (!default_gpg_agent_info)
445 0 : return SPWQ_OUT_OF_CORE;
446 : /* We don't know the PID thus we use 0. */
447 10 : strcpy (stpcpy (default_gpg_agent_info, name),
448 : PATHSEP_S "0" PATHSEP_S "1");
449 : }
450 : else
451 0 : default_gpg_agent_info = NULL;
452 :
453 10 : return 0;
454 : }
455 :
456 :
457 : /* Ask the gpg-agent for a passphrase and present the user with a
458 : DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
459 : If a CACHEID is not NULL it is used to locate the passphrase in in
460 : the cache and store it under this ID. If OPT_CHECK is true
461 : gpg-agent is asked to apply some checks on the passphrase security.
462 : If ERRORCODE is not NULL it should point a variable receiving an
463 : errorcode; this error code might be 0 if the user canceled the
464 : operation. The function returns NULL to indicate an error. */
465 : char *
466 0 : simple_pwquery (const char *cacheid,
467 : const char *tryagain,
468 : const char *prompt,
469 : const char *description,
470 : int opt_check,
471 : int *errorcode)
472 : {
473 0 : int fd = -1;
474 : int nread;
475 0 : char *result = NULL;
476 0 : char *pw = NULL;
477 : char *p;
478 : int rc, i;
479 :
480 0 : rc = agent_open (&fd);
481 0 : if (rc)
482 0 : goto leave;
483 :
484 0 : if (!cacheid)
485 0 : cacheid = "X";
486 0 : if (!tryagain)
487 0 : tryagain = "X";
488 0 : if (!prompt)
489 0 : prompt = "X";
490 0 : if (!description)
491 0 : description = "X";
492 :
493 : {
494 : char *line;
495 : /* We allocate 3 times the needed space so that there is enough
496 : space for escaping. */
497 0 : line = spwq_malloc (15 + 10
498 : + 3*strlen (cacheid) + 1
499 : + 3*strlen (tryagain) + 1
500 : + 3*strlen (prompt) + 1
501 : + 3*strlen (description) + 1
502 : + 2);
503 0 : if (!line)
504 : {
505 0 : rc = SPWQ_OUT_OF_CORE;
506 0 : goto leave;
507 : }
508 0 : strcpy (line, "GET_PASSPHRASE ");
509 0 : p = line+15;
510 0 : if (opt_check)
511 0 : p = stpcpy (p, "--check ");
512 0 : p = copy_and_escape (p, cacheid);
513 0 : *p++ = ' ';
514 0 : p = copy_and_escape (p, tryagain);
515 0 : *p++ = ' ';
516 0 : p = copy_and_escape (p, prompt);
517 0 : *p++ = ' ';
518 0 : p = copy_and_escape (p, description);
519 0 : *p++ = '\n';
520 0 : rc = writen (fd, line, p - line);
521 0 : spwq_free (line);
522 0 : if (rc)
523 0 : goto leave;
524 : }
525 :
526 : /* get response */
527 0 : pw = spwq_secure_malloc (500);
528 0 : nread = readline (fd, pw, 499);
529 0 : if (nread < 0)
530 : {
531 0 : rc = -nread;
532 0 : goto leave;
533 : }
534 0 : if (nread < 3)
535 : {
536 0 : rc = SPWQ_PROTOCOL_ERROR;
537 0 : goto leave;
538 : }
539 :
540 0 : if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
541 0 : { /* we got a passphrase - convert it back from hex */
542 0 : size_t pwlen = 0;
543 :
544 0 : for (i=3; i < nread && hexdigitp (pw+i); i+=2)
545 0 : pw[pwlen++] = xtoi_2 (pw+i);
546 0 : pw[pwlen] = 0; /* make a C String */
547 0 : result = pw;
548 0 : pw = NULL;
549 : }
550 0 : else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
551 0 : && (pw[7] == ' ' || pw[7] == '\n') )
552 0 : || ((nread > 4 && !memcmp (pw, "ERR ", 4)
553 0 : && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) )
554 : {
555 : /* 111 is the old Assuan code for canceled which might still
556 : be in use by old installations. 99 is GPG_ERR_CANCELED as
557 : used by modern gpg-agents; 0xffff is used to mask out the
558 : error source. */
559 : #ifdef SPWQ_USE_LOGGING
560 0 : log_info (_("canceled by user\n") );
561 : #endif
562 0 : *errorcode = 0; /* Special error code to indicate Cancel. */
563 : }
564 0 : else if (nread > 4 && !memcmp (pw, "ERR ", 4))
565 : {
566 0 : switch ( (strtoul (pw+4, NULL, 0) & 0xffff) )
567 : {
568 0 : case 85: rc = SPWQ_NO_PIN_ENTRY; break;
569 0 : default: rc = SPWQ_GENERAL_ERROR; break;
570 : }
571 0 : }
572 : else
573 : {
574 : #ifdef SPWQ_USE_LOGGING
575 0 : log_error (_("problem with the agent\n"));
576 : #endif
577 0 : rc = SPWQ_ERR_RESPONSE;
578 : }
579 :
580 : leave:
581 0 : if (errorcode)
582 0 : *errorcode = rc;
583 0 : if (fd != -1)
584 0 : close (fd);
585 0 : if (pw)
586 0 : spwq_secure_free (pw);
587 0 : return result;
588 : }
589 :
590 :
591 : /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
592 : int
593 0 : simple_pwclear (const char *cacheid)
594 : {
595 : char line[500];
596 : char *p;
597 :
598 : /* We need not more than 50 characters for the command and the
599 : terminating nul. */
600 0 : if (strlen (cacheid) * 3 > sizeof (line) - 50)
601 0 : return SPWQ_PROTOCOL_ERROR;
602 :
603 0 : strcpy (line, "CLEAR_PASSPHRASE ");
604 0 : p = line + 17;
605 0 : p = copy_and_escape (p, cacheid);
606 0 : *p++ = '\n';
607 0 : *p++ = '\0';
608 :
609 0 : return simple_query (line);
610 : }
611 :
612 :
613 : /* Perform the simple query QUERY (which must be new-line and 0
614 : terminated) and return the error code. */
615 : int
616 10 : simple_query (const char *query)
617 : {
618 10 : int fd = -1;
619 : int nread;
620 : char response[500];
621 : int rc;
622 :
623 10 : rc = agent_open (&fd);
624 10 : if (rc)
625 0 : goto leave;
626 :
627 10 : rc = writen (fd, query, strlen (query));
628 10 : if (rc)
629 0 : goto leave;
630 :
631 : /* get response */
632 10 : nread = readline (fd, response, 499);
633 10 : if (nread < 0)
634 : {
635 0 : rc = -nread;
636 0 : goto leave;
637 : }
638 10 : if (nread < 3)
639 : {
640 0 : rc = SPWQ_PROTOCOL_ERROR;
641 0 : goto leave;
642 : }
643 :
644 10 : if (response[0] == 'O' && response[1] == 'K')
645 : /* OK, do nothing. */;
646 0 : else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
647 0 : && (response[7] == ' ' || response[7] == '\n') )
648 0 : || ((nread > 4 && !memcmp (response, "ERR ", 4)
649 0 : && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
650 : {
651 : /* 111 is the old Assuan code for canceled which might still
652 : be in use by old installations. 99 is GPG_ERR_CANCELED as
653 : used by modern gpg-agents; 0xffff is used to mask out the
654 : error source. */
655 : #ifdef SPWQ_USE_LOGGING
656 0 : log_info (_("canceled by user\n") );
657 : #endif
658 : }
659 : else
660 : {
661 : #ifdef SPWQ_USE_LOGGING
662 0 : log_error (_("problem with the agent\n"));
663 : #endif
664 0 : rc = SPWQ_ERR_RESPONSE;
665 : }
666 :
667 : leave:
668 10 : if (fd != -1)
669 10 : close (fd);
670 10 : return rc;
671 : }
|