Send SIGINT rather than SIGTERM to terminate the local pinentry.
[libpwmd.git] / src / libpwmd.c
bloba812b192549d23ae3ccffcc772cb6c5e45ef0c57
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd 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 2 of the License, or
10 (at your option) any later version.
12 Libpwmd 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 Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <err.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <sys/wait.h>
38 #include <fcntl.h>
39 #include <pwd.h>
40 #include <time.h>
41 #include <limits.h>
42 #include <sys/select.h>
43 #include <termios.h>
44 #include <libpwmd.h>
46 #ifdef HAVE_STRINGS_H
47 #include <strings.h>
48 #endif
50 #ifndef LINE_MAX
51 #define LINE_MAX 2048
52 #endif
54 #include "mem.h"
55 #include "misc.h"
56 #include "types.h"
58 #ifdef WITH_PINENTRY
59 #include "pinentry.h"
60 #endif
62 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <netdb.h>
66 #include <netinet/in.h>
67 #endif
69 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
70 ? gpg_error(rc) : rc
72 typedef struct
74 size_t len;
75 void *buf;
76 } membuf_t;
78 ssize_t
79 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
81 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
82 pwm_t *pwm = assuan_get_pointer (ctx);
84 #ifdef WITH_SSH
85 if (pwm && pwm->tcp && pwm->tcp->ssh)
86 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
87 #endif
88 #ifdef WITH_GNUTLS
89 if (pwm && pwm->tcp && pwm->tcp->tls)
90 return read_hook_tls (pwm->tcp->tls, fd, data, len);
91 #endif
92 #endif
94 return read ((int) fd, data, len);
97 ssize_t
98 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
99 size_t len)
101 ssize_t wrote;
102 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
103 pwm_t *pwm = assuan_get_pointer (ctx);
105 #ifdef WITH_SSH
106 if (pwm && pwm->tcp && pwm->tcp->ssh)
107 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
108 #endif
109 #ifdef WITH_GNUTLS
110 if (pwm && pwm->tcp && pwm->tcp->tls)
111 return write_hook_tls (pwm->tcp->tls, fd, data, len);
112 #endif
113 #endif
115 /* libassuan cannot handle EAGAIN when doing writes. */
118 wrote = write ((int) fd, data, len);
119 if (wrote == -1 && errno == EAGAIN)
120 usleep (50000);
122 while (wrote == -1 && errno == EAGAIN);
124 return wrote;
127 pid_t
128 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
129 int options)
131 return waitpid (pid, status, options);
134 gpg_error_t
135 pwmd_init ()
137 static int initialized;
139 #ifdef WITH_GNUTLS
140 // May be called more than once.
141 gnutls_global_init ();
142 #endif
144 if (initialized)
145 return 0;
147 #ifndef MEM_DEBUG
148 _xmem_init ();
149 #endif
150 #ifdef ENABLE_NLS
151 bindtextdomain ("libpwmd", LOCALEDIR);
152 #endif
153 #ifdef WITH_SSH
154 libssh2_init (0);
155 #endif
156 gpg_err_init ();
157 initialized = 1;
158 return 0;
161 void
162 pwmd_deinit ()
164 #ifdef WITH_GNUTLS
165 gnutls_global_deinit ();
166 #endif
169 gpg_error_t
170 _connect_finalize (pwm_t * pwm)
172 gpg_error_t rc = 0;
173 int active[2];
174 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
176 if (n <= 0)
177 return GPG_ERR_EBADFD;
179 pwm->fd = active[0];
180 #ifdef WITH_PINENTRY
181 pwm->pinentry_pid = -1;
182 #endif
184 if (pwm->name)
185 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
186 pwm->name);
188 return rc;
191 static gpg_error_t
192 connect_uds (pwm_t * pwm, const char *path)
194 char *socketpath = NULL;
195 struct passwd pw;
196 char *pwbuf;
197 gpg_error_t rc;
199 if (!pwm)
200 return GPG_ERR_INV_ARG;
202 pwbuf = _getpwuid (&pw);
203 if (!pwbuf)
204 return gpg_error_from_syserror ();
206 if (!path || !*path)
207 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
208 else
209 socketpath = _expand_homedir ((char *) path, &pw);
211 pwmd_free (pwbuf);
212 if (!socketpath)
213 return GPG_ERR_ENOMEM;
215 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
216 pwmd_free (socketpath);
217 return rc ? rc : _connect_finalize (pwm);
220 static gpg_error_t
221 init_handle (pwm_t * pwm)
223 gpg_error_t rc;
224 static struct assuan_malloc_hooks mhooks = {
225 pwmd_malloc, pwmd_realloc, pwmd_free
227 static struct assuan_system_hooks shooks = {
228 ASSUAN_SYSTEM_HOOKS_VERSION,
229 __assuan_usleep,
230 __assuan_pipe,
231 __assuan_close,
232 hook_read,
233 hook_write,
234 //FIXME
235 NULL, //recvmsg
236 NULL, //sendmsg both are used for FD passing
237 __assuan_spawn,
238 hook_waitpid,
239 __assuan_socketpair,
240 __assuan_socket,
241 __assuan_connect
244 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
245 NULL);
246 if (rc)
247 return rc;
249 assuan_set_pointer (pwm->ctx, pwm);
250 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
251 return 0;
254 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
255 void
256 free_tcp (struct tcp_s *tcp)
258 if (!tcp)
259 return;
261 #ifdef WITH_SSH
262 _free_ssh_conn (tcp->ssh);
263 #endif
264 #ifdef WITH_GNUTLS
265 tls_free (tcp->tls);
266 #endif
268 pwmd_free (tcp->host);
269 if (tcp->addrs)
271 freeaddrinfo (tcp->addrs);
272 tcp->addrs = NULL;
275 pwmd_free (tcp);
277 #endif
279 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
280 gpg_error_t
281 tcp_connect_common (pwm_t * pwm)
283 struct addrinfo hints = { 0 };
284 int n;
285 char portstr[6];
286 gpg_error_t rc = 0;
288 switch (pwm->prot)
290 case PWMD_IP_ANY:
291 hints.ai_family = AF_UNSPEC;
292 break;
293 case PWMD_IPV4:
294 hints.ai_family = AF_INET;
295 break;
296 case PWMD_IPV6:
297 hints.ai_family = AF_INET6;
298 break;
301 hints.ai_socktype = SOCK_STREAM;
302 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
303 n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
304 if (n)
306 fprintf (stderr, "%s\n", gai_strerror (n));
307 return GPG_ERR_UNKNOWN_HOST; //FIXME
310 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
311 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
313 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
314 if (pwm->fd == -1)
316 rc = gpg_error_from_syserror ();
317 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
318 break;
319 continue;
322 if (pwm->socket_timeout)
323 fcntl (pwm->fd, F_SETFL, O_NONBLOCK);
325 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
326 pwm->tcp->addr->ai_family == AF_INET6
327 ? sizeof (struct sockaddr_in6)
328 : sizeof (struct sockaddr)) == -1)
330 int n;
331 struct timeval tv = { pwm->socket_timeout, 0 };
332 fd_set wfds;
334 rc = gpg_error_from_syserror ();
335 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
337 close (pwm->fd);
338 pwm->fd = -1;
339 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
340 return rc;
343 FD_ZERO (&wfds);
344 FD_SET (pwm->fd, &wfds);
345 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
346 rc = 0;
347 if (!n)
348 rc = gpg_error (GPG_ERR_ETIMEDOUT);
349 else if (n != -1)
351 socklen_t len;
353 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
354 if (n)
355 rc = gpg_error_from_errno (n);
357 else if (n == -1)
358 rc = gpg_error_from_syserror ();
360 if (rc)
362 close (pwm->fd);
363 pwm->fd = -1;
364 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
365 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT)
366 return rc;
368 else
369 break;
371 else
372 break;
375 if (!rc && pwm->socket_timeout)
376 fcntl (pwm->fd, F_SETFL, 0);
378 return rc;
380 #endif
382 gpg_error_t
383 pwmd_connect (pwm_t * pwm, const char *url, ...)
385 const char *p = url;
386 gpg_error_t rc;
388 if (!pwm)
389 return FINISH (GPG_ERR_INV_ARG);
390 else if (!pwm->ctx)
392 rc = init_handle (pwm);
393 if (rc)
394 return rc;
397 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
399 if (p && *p == '/')
400 rc = connect_uds (pwm, p);
401 else if (!p || !strncmp (p, "file://", 7))
403 if (p)
404 p += 7;
405 rc = connect_uds (pwm, p);
407 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
408 !strncmp (p, "ssh4://", 7))
410 #ifndef WITH_SSH
411 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
412 #else
413 char *host = NULL;
414 int port;
415 char *username = NULL;
417 if (!strncmp (p, "ssh6://", 7))
419 pwm->prot = PWMD_IPV6;
420 p += 7;
422 else if (!strncmp (p, "ssh4://", 7))
424 pwm->prot = PWMD_IPV4;
425 p += 7;
427 else
429 pwm->prot = PWMD_IP_ANY;
430 p += 6;
433 rc = _parse_ssh_url (p, &host, &port, &username);
434 if (!rc)
436 va_list ap;
437 char *identity = NULL;
438 char *knownhosts = NULL;
440 va_start (ap, url);
441 identity = va_arg (ap, char *);
443 if (!identity && !pwm->use_agent)
444 rc = GPG_ERR_INV_ARG;
445 else
446 knownhosts = va_arg (ap, char *);
448 va_end (ap);
450 if (!rc)
451 rc = _do_ssh_connect (pwm, host, port, identity, username,
452 knownhosts);
453 if (!rc)
455 rc = _connect_finalize (pwm);
456 if (rc)
458 free_tcp (pwm->tcp);
459 pwm->tcp = NULL;
464 pwmd_free (host);
465 pwmd_free (username);
466 return FINISH (rc);
467 #endif
469 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
470 !strncmp (p, "tls4://", 7))
472 #ifndef WITH_GNUTLS
473 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
474 #else
475 char *host = NULL;
476 int port;
478 if (!strncmp (p, "tls6://", 7))
480 pwm->prot = PWMD_IPV6;
481 p += 7;
483 else if (!strncmp (p, "tls4://", 7))
485 pwm->prot = PWMD_IPV4;
486 p += 7;
488 else
490 pwm->prot = PWMD_IP_ANY;
491 p += 6;
494 rc = _parse_tls_url (p, &host, &port);
495 if (!rc)
497 va_list ap;
498 char *clientcert = NULL;
499 char *clientkey = NULL;
500 char *cacert = NULL;
501 char *prio = NULL;
502 char *server_fp = NULL;
504 va_start (ap, url);
505 clientcert = va_arg (ap, char *);
507 if (!clientcert)
508 rc = GPG_ERR_INV_ARG;
509 else
511 clientkey = va_arg (ap, char *);
512 if (!clientkey)
513 rc = GPG_ERR_INV_ARG;
514 else
516 cacert = va_arg (ap, char *);
517 if (!cacert)
518 rc = GPG_ERR_INV_ARG;
519 else
521 prio = va_arg (ap, char *);
522 server_fp = va_arg (ap, char *);
527 va_end (ap);
529 if (!rc)
530 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
531 cacert, prio, server_fp, pwm->tls_verify);
532 if (!rc)
534 rc = _connect_finalize (pwm);
535 if (rc)
537 free_tcp (pwm->tcp);
538 pwm->tcp = NULL;
543 pwmd_free (host);
544 return FINISH (rc);
545 #endif
548 return FINISH (rc);
551 static void
552 disconnect (pwm_t * pwm)
554 if (!pwm)
555 return;
557 if (pwm->ctx)
558 assuan_release (pwm->ctx);
560 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
561 free_tcp (pwm->tcp);
562 pwm->tcp = NULL;
563 #endif
564 pwm->ctx = NULL;
565 pwm->fd = -1;
568 void
569 pwmd_close (pwm_t * pwm)
571 if (!pwm)
572 return;
574 disconnect (pwm);
575 pwmd_free (pwm->pinentry_error);
576 pwmd_free (pwm->pinentry_desc);
577 pwmd_free (pwm->pinentry_prompt);
578 pwmd_free (pwm->pinentry_tty);
579 pwmd_free (pwm->pinentry_display);
580 pwmd_free (pwm->pinentry_term);
581 pwmd_free (pwm->pinentry_lcctype);
582 pwmd_free (pwm->pinentry_lcmessages);
583 pwmd_free (pwm->filename);
584 pwmd_free (pwm->name);
586 #ifdef WITH_PINENTRY
587 if (pwm->pctx)
588 _pinentry_disconnect (pwm);
589 #endif
591 pwmd_free (pwm);
594 static gpg_error_t
595 inquire_realloc_cb (void *data, const void *buffer, size_t len)
597 membuf_t *mem = (membuf_t *) data;
598 void *p;
600 if (!buffer)
601 return 0;
603 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
604 return gpg_error (GPG_ERR_ENOMEM);
606 mem->buf = p;
607 memcpy ((char *) mem->buf + mem->len, buffer, len);
608 mem->len += len;
609 return 0;
612 static gpg_error_t
613 get_password (pwm_t * pwm, char **result, size_t * len,
614 pwmd_pinentry_t w, int echo)
616 char buf[LINE_MAX] = { 0 }, *p;
617 struct termios told, tnew;
618 char *key = NULL;
620 if (result)
621 *result = NULL;
623 if (len)
624 *len = 0;
626 if (!isatty (STDIN_FILENO))
628 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
629 return GPG_ERR_ENOTTY;
632 if (!echo)
634 if (tcgetattr (STDIN_FILENO, &told) == -1)
635 return gpg_error_from_syserror ();
637 memcpy (&tnew, &told, sizeof (struct termios));
638 tnew.c_lflag &= ~(ECHO);
639 tnew.c_lflag |= ICANON | ECHONL;
641 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
643 int n = errno;
645 tcsetattr (STDIN_FILENO, TCSANOW, &told);
646 return gpg_error_from_errno (n);
650 switch (w)
652 case PWMD_PINENTRY_OPEN:
653 fprintf (stderr, N_("Password for %s: "), pwm->filename);
654 break;
655 case PWMD_PINENTRY_OPEN_FAILED:
656 fprintf (stderr, N_("Invalid password. Password for %s: "),
657 pwm->filename);
658 break;
659 case PWMD_PINENTRY_SAVE:
660 fprintf (stderr, N_("New password for %s: "), pwm->filename);
661 break;
662 case PWMD_PINENTRY_SAVE_CONFIRM:
663 fprintf (stderr, N_("Confirm password: "));
664 break;
665 default:
666 break;
669 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
671 tcsetattr (STDIN_FILENO, TCSANOW, &told);
672 return 0;
675 if (!echo)
676 tcsetattr (STDIN_FILENO, TCSANOW, &told);
678 if (feof (stdin))
680 clearerr (stdin);
681 return GPG_ERR_CANCELED;
684 /* Strip the newline character. */
685 p[strlen (p) - 1] = 0;
687 if (buf[0])
689 key = pwmd_strdup_printf ("%s", p);
690 memset (buf, 0, sizeof (buf));
691 if (!key)
692 return GPG_ERR_ENOMEM;
694 if (result)
695 *result = key;
697 if (len)
698 *len = strlen (key);
700 else
702 if (result)
703 *result = pwmd_strdup ("");
705 if (len)
706 *len = 1;
709 return 0;
712 gpg_error_t
713 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
715 gpg_error_t rc;
716 int new_password = 0;
717 char *password = NULL, *newpass = NULL;
718 int error = 0;
720 if (data)
721 *data = NULL;
723 if (size)
724 *size = 0;
726 if (!strcmp (keyword, "NEW_PASSPHRASE"))
727 new_password = 1;
729 if (!new_password && pwm->pinentry_try)
730 error = 1;
732 again:
733 if (pwm->disable_pinentry)
735 rc = get_password (pwm, &password, size,
736 new_password ? PWMD_PINENTRY_SAVE :
737 error ? PWMD_PINENTRY_OPEN_FAILED :
738 PWMD_PINENTRY_OPEN, 0);
739 if (!rc && new_password)
740 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
743 else
745 pwmd_pinentry_t which;
747 if (error)
748 which = new_password
749 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
750 else
751 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
753 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
754 if (!rc && new_password)
755 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
756 PWMD_PINENTRY_SAVE_CONFIRM);
759 if (!rc && new_password)
761 if ((!password && newpass) || (!newpass && password)
762 || strcmp (newpass, password))
764 if (pwm->disable_pinentry)
765 fprintf (stderr, N_("Passphrases do not match.\n"));
767 pwmd_free (password);
768 pwmd_free (newpass);
769 password = newpass = NULL;
770 error = 1;
771 goto again;
775 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
776 pwmd_free (newpass);
777 if (!rc && data)
778 *data = password;
780 return rc;
783 static gpg_error_t
784 inquire_cb (void *data, const char *keyword)
786 pwm_t *pwm = (pwm_t *) data;
787 gpg_error_t rc = 0;
788 int free_result = 0;
789 char *result = NULL;
790 int is_password = 0;
791 int new_password = 0;
793 if (!strcmp (keyword, "PASSPHRASE"))
794 is_password = 1;
795 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
796 new_password = 1;
798 /* Shouldn't get this far without a callback. */
799 if (!pwm->override_inquire && !pwm->inquire_func
800 && !is_password && !new_password)
801 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
803 for (;;)
805 size_t len = 0;
806 gpg_error_t arc;
808 result = NULL;
810 if (!pwm->override_inquire && (is_password || new_password))
812 free_result = 1;
813 rc = pwmd_password (data, keyword, &result, &len);
814 if (!rc)
815 rc = GPG_ERR_EOF;
817 else
818 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
819 &len);
821 cancel:
822 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
824 #ifndef LIBASSUAN_2_1_0
825 gpg_error_t trc = rc;
827 /* Cancel this inquire. */
828 rc = assuan_send_data (pwm->ctx, NULL, 1);
829 if (!rc)
831 char *line;
832 size_t len;
834 /* There is a bug (or feature?) in assuan_send_data() that
835 * when cancelling an inquire the next read from the server is
836 * not done until the next command making the next command
837 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
839 rc = assuan_read_line (pwm->ctx, &line, &len);
841 /* Restore the original error. This differs from the error
842 * returned from the pwmd command (GPG_ERR_CANCELED). This
843 * error is returned to the calling function.
845 if (!rc)
846 rc = trc;
848 #endif
849 break;
852 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
854 if (len <= 0 && !result)
856 rc = 0;
857 break;
859 else if ((len <= 0 && result) || (len && !result))
861 rc = gpg_error (GPG_ERR_INV_ARG);
862 break;
865 if (pwm->inquire_maxlen
866 && pwm->inquire_sent + len > pwm->inquire_maxlen)
868 rc = gpg_error (GPG_ERR_TOO_LARGE);
869 if (!free_result)
870 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
871 &result, &len);
872 goto cancel;
875 arc = assuan_send_data (pwm->ctx, result, len);
876 if (gpg_err_code (rc) == GPG_ERR_EOF)
878 rc = arc;
879 break;
882 rc = arc;
884 else if (rc)
885 break;
887 if (!rc)
889 pwm->inquire_sent += len;
891 if (pwm->status_func)
893 char buf[ASSUAN_LINELENGTH];
895 snprintf (buf, sizeof (buf), "XFER %lu %lu", pwm->inquire_sent,
896 pwm->inquire_total);
897 rc = pwm->status_func (pwm->status_data, buf);
898 if (rc)
899 continue;
904 if (free_result)
905 pwmd_free (result);
907 return rc;
910 static gpg_error_t
911 parse_assuan_line (pwm_t * pwm)
913 gpg_error_t rc;
914 char *line;
915 size_t len;
917 rc = assuan_read_line (pwm->ctx, &line, &len);
918 if (!rc)
920 if (line[0] == 'O' && line[1] == 'K' &&
921 (line[2] == 0 || line[2] == ' '))
924 else if (line[0] == '#')
927 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
929 if (pwm->status_func)
931 rc = pwm->status_func (pwm->status_data,
932 line[1] == 0 ? line + 1 : line + 2);
935 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
936 (line[3] == 0 || line[3] == ' '))
938 line += 4;
939 rc = strtol (line, NULL, 10);
943 return rc;
946 static void
947 reset_handle_state (pwm_t * pwm, int done)
949 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
950 if (pwm->tcp)
951 pwm->tcp->rc = 0;
953 if (done)
955 free_tcp (pwm->tcp);
956 pwm->tcp = NULL;
958 #endif
961 static void
962 reset_handle (pwm_t * h)
964 h->fd = -1;
965 #ifdef WITH_PINENTRY
966 if (h->pctx)
967 _pinentry_disconnect (h);
968 #endif
969 reset_handle_state (h, 0);
972 gpg_error_t
973 pwmd_disconnect (pwm_t * pwm)
975 if (!pwm)
976 return FINISH (GPG_ERR_INV_ARG);
978 if (pwm->fd == -1)
979 return FINISH (GPG_ERR_INV_STATE);
981 disconnect (pwm);
982 reset_handle (pwm);
983 return 0;
986 /* Note that this should only be called when not in a command. */
987 gpg_error_t
988 pwmd_process (pwm_t * pwm)
990 gpg_error_t rc = 0;
991 fd_set fds;
992 struct timeval tv = { 0, 0 };
993 int n;
995 if (!pwm)
996 return FINISH (GPG_ERR_INV_ARG);
997 else if (!pwm->ctx)
998 return FINISH (GPG_ERR_INV_STATE);
1000 FD_ZERO (&fds);
1001 FD_SET (pwm->fd, &fds);
1002 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1004 if (n == -1)
1005 return FINISH (gpg_error_from_syserror ());
1007 if (n > 0)
1009 if (FD_ISSET (pwm->fd, &fds))
1010 rc = parse_assuan_line (pwm);
1013 while (!rc && assuan_pending_line (pwm->ctx))
1014 rc = parse_assuan_line (pwm);
1016 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1017 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1019 close (pwm->fd);
1020 pwm->fd = -1;
1022 #endif
1024 return FINISH (rc);
1027 static gpg_error_t
1028 status_cb (void *data, const char *line)
1030 pwm_t *pwm = data;
1032 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1033 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1035 if (pwm->status_func)
1036 return pwm->status_func (pwm->status_data, line);
1038 return 0;
1041 gpg_error_t
1042 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1043 char **result, size_t * len, const char *cmd)
1045 membuf_t data;
1046 gpg_error_t rc;
1048 if (!cmd || !*cmd)
1049 return FINISH (GPG_ERR_INV_ARG);
1051 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1052 return FINISH (GPG_ERR_LINE_TOO_LONG);
1054 data.len = 0;
1055 data.buf = NULL;
1056 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1057 #ifdef WITH_QUALITY
1058 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1059 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1060 #else
1061 inquire_cb, pwm,
1062 #endif
1063 status_cb, pwm);
1065 if (rc)
1067 if (data.buf)
1069 pwmd_free (data.buf);
1070 data.buf = NULL;
1073 else
1075 if (data.buf)
1077 inquire_realloc_cb (&data, "", 1);
1079 if (result)
1080 *result = (char *) data.buf;
1081 else
1082 pwmd_free (data.buf);
1084 if (len)
1085 *len = data.len;
1089 pwm->inquire_maxlen = 0;
1090 return rc;
1093 gpg_error_t
1094 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1095 pwmd_inquire_cb_t func, void *user, const char *cmd,
1096 va_list ap)
1098 char *buf;
1099 size_t len;
1100 va_list ap2;
1102 if (!pwm || !cmd)
1103 return FINISH (GPG_ERR_INV_ARG);
1104 if (!pwm->ctx)
1105 return FINISH (GPG_ERR_INV_STATE);
1108 * C99 allows the dst pointer to be null which will calculate the length
1109 * of the would-be result and return it.
1111 va_copy (ap2, ap);
1112 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1113 buf = (char *) pwmd_malloc (len);
1114 if (!buf)
1116 va_end (ap2);
1117 return FINISH (GPG_ERR_ENOMEM);
1120 len = vsnprintf (buf, len, cmd, ap2);
1121 va_end (ap2);
1123 if (buf[strlen (buf) - 1] == '\n')
1124 buf[strlen (buf) - 1] = 0;
1125 if (buf[strlen (buf) - 1] == '\r')
1126 buf[strlen (buf) - 1] = 0;
1128 pwm->inquire_func = func;
1129 pwm->inquire_data = user;
1130 pwm->inquire_sent = 0;
1131 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1132 pwmd_free (buf);
1133 return rc;
1136 gpg_error_t
1137 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1138 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1140 va_list ap;
1142 if (!pwm || !cmd)
1143 return FINISH (GPG_ERR_INV_ARG);
1144 if (!pwm->ctx)
1145 return FINISH (GPG_ERR_INV_STATE);
1147 if (result)
1148 *result = NULL;
1150 va_start (ap, cmd);
1151 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1152 va_end (ap);
1153 return rc;
1156 static gpg_error_t
1157 send_pinentry_options (pwm_t * pwm)
1159 gpg_error_t rc;
1161 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1162 "OPTION disable-pinentry=0");
1163 if (rc)
1164 return rc;
1166 if (pwm->pinentry_tty)
1168 rc =
1169 pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1170 pwm->pinentry_tty);
1171 if (rc)
1172 return rc;
1175 if (pwm->pinentry_term)
1177 rc =
1178 pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1179 pwm->pinentry_term);
1180 if (rc)
1181 return rc;
1184 if (pwm->pinentry_display)
1186 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1187 pwm->pinentry_display);
1188 if (rc)
1189 return rc;
1192 if (pwm->pinentry_desc)
1194 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1195 pwm->pinentry_desc);
1196 if (rc)
1197 return rc;
1200 if (pwm->pinentry_lcctype)
1202 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1203 pwm->pinentry_lcctype);
1204 if (rc)
1205 return rc;
1208 if (pwm->pinentry_lcmessages)
1210 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1211 pwm->pinentry_lcmessages);
1212 if (rc)
1213 return rc;
1216 return 0;
1219 gpg_error_t
1220 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1222 if (!pwm || !result)
1223 return FINISH (GPG_ERR_INV_ARG);
1225 *result = PWMD_SOCKET_LOCAL;
1227 if (pwm->fd == -1)
1228 return FINISH (GPG_ERR_INV_STATE);
1230 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1231 #ifdef WITH_SSH
1232 if (pwm->tcp && pwm->tcp->ssh)
1233 *result = PWMD_SOCKET_SSH;
1234 #endif
1235 #ifdef WITH_GNUTLS
1236 if (pwm->tcp && pwm->tcp->tls)
1237 *result = PWMD_SOCKET_TLS;
1238 #endif
1239 #endif
1240 return 0;
1243 gpg_error_t
1244 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1245 void *data)
1247 gpg_error_t rc = 0;
1248 int no_pinentry;
1250 if (!pwm || !filename || !*filename)
1251 return FINISH (GPG_ERR_INV_ARG);
1253 if (!pwm->ctx)
1254 return FINISH (GPG_ERR_INV_STATE);
1256 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1257 no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1258 #else
1259 no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1260 #endif
1262 if (!no_pinentry)
1263 rc = send_pinentry_options (pwm);
1264 else
1265 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1266 "OPTION disable-pinentry");
1268 if (!rc)
1270 pwm->pinentry_try = 0;
1271 pwmd_free (pwm->filename);
1272 pwm->filename = pwmd_strdup (filename);
1276 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1277 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1278 filename);
1280 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1281 && no_pinentry && ++pwm->pinentry_try < pwm->pinentry_tries);
1283 pwm->pinentry_try = 0;
1285 if (rc)
1287 pwmd_free (pwm->filename);
1288 pwm->filename = NULL;
1292 return FINISH (rc);
1295 gpg_error_t
1296 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1298 gpg_error_t rc;
1300 if (!pwm)
1301 return FINISH (GPG_ERR_INV_ARG);
1302 if (!pwm->ctx)
1303 return FINISH (GPG_ERR_INV_STATE);
1305 rc = pwmd_command (pwm, NULL, NULL, cb, data, "SAVE %s", args ? args : "");
1306 return FINISH (rc);
1309 gpg_error_t
1310 pwmd_setopt (pwm_t * pwm, pwmd_option_t opt, ...)
1312 va_list ap;
1313 int n;
1314 char *arg1;
1315 gpg_error_t rc = 0;
1317 if (!pwm)
1318 return FINISH (GPG_ERR_INV_ARG);
1320 va_start (ap, opt);
1322 switch (opt)
1324 case PWMD_OPTION_LOCK_ON_OPEN:
1325 n = va_arg (ap, int);
1327 if (n < 0 || n > 1)
1328 rc = GPG_ERR_INV_VALUE;
1330 if (n)
1331 pwm->opts |= OPT_LOCK_ON_OPEN;
1332 else
1333 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1335 break;
1336 case PWMD_OPTION_INQUIRE_TOTAL:
1337 pwm->inquire_total = va_arg (ap, size_t);
1338 break;
1339 case PWMD_OPTION_STATUS_CB:
1340 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1341 break;
1342 case PWMD_OPTION_STATUS_DATA:
1343 pwm->status_data = va_arg (ap, void *);
1344 break;
1345 case PWMD_OPTION_NO_PINENTRY:
1346 n = va_arg (ap, int);
1348 if (n < 0 || n > 1)
1349 rc = GPG_ERR_INV_VALUE;
1350 else
1351 pwm->disable_pinentry = n;
1353 break;
1354 case PWMD_OPTION_LOCAL_PINENTRY:
1355 n = va_arg (ap, int);
1357 if (n < 0 || n > 1)
1358 rc = GPG_ERR_INV_VALUE;
1359 else
1360 pwm->local_pinentry = n;
1362 break;
1363 case PWMD_OPTION_PINENTRY_TIMEOUT:
1364 n = va_arg (ap, int);
1366 if (n < 0)
1367 rc = GPG_ERR_INV_VALUE;
1368 else
1369 pwm->pinentry_timeout = n;
1371 break;
1372 case PWMD_OPTION_PINENTRY_TRIES:
1373 n = va_arg (ap, int);
1374 pwm->pinentry_tries = n;
1375 break;
1376 case PWMD_OPTION_PINENTRY_PATH:
1377 arg1 = va_arg (ap, char *);
1378 pwmd_free (pwm->pinentry_path);
1379 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1380 break;
1381 case PWMD_OPTION_PINENTRY_TTY:
1382 arg1 = va_arg (ap, char *);
1383 pwmd_free (pwm->pinentry_tty);
1384 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1385 break;
1386 case PWMD_OPTION_PINENTRY_DISPLAY:
1387 arg1 = va_arg (ap, char *);
1388 pwmd_free (pwm->pinentry_display);
1389 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1390 break;
1391 case PWMD_OPTION_PINENTRY_TERM:
1392 arg1 = va_arg (ap, char *);
1393 pwmd_free (pwm->pinentry_term);
1394 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1395 break;
1396 case PWMD_OPTION_PINENTRY_ERROR:
1397 arg1 = va_arg (ap, char *);
1398 pwmd_free (pwm->pinentry_error);
1399 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1400 break;
1401 case PWMD_OPTION_PINENTRY_PROMPT:
1402 arg1 = va_arg (ap, char *);
1403 pwmd_free (pwm->pinentry_prompt);
1404 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1405 break;
1406 case PWMD_OPTION_PINENTRY_DESC:
1407 arg1 = va_arg (ap, char *);
1408 pwmd_free (pwm->pinentry_desc);
1409 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1410 break;
1411 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1412 arg1 = va_arg (ap, char *);
1413 pwmd_free (pwm->pinentry_lcctype);
1414 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1415 break;
1416 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1417 arg1 = va_arg (ap, char *);
1418 pwmd_free (pwm->pinentry_lcmessages);
1419 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1420 break;
1421 case PWMD_OPTION_KNOWNHOST_CB:
1422 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1423 break;
1424 case PWMD_OPTION_KNOWNHOST_DATA:
1425 pwm->kh_data = va_arg (ap, void *);
1426 break;
1427 case PWMD_OPTION_SSH_AGENT:
1428 pwm->use_agent = va_arg (ap, int);
1430 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1432 pwm->use_agent = 0;
1433 rc = GPG_ERR_INV_VALUE;
1435 break;
1436 case PWMD_OPTION_TLS_VERIFY:
1437 pwm->tls_verify = va_arg (ap, int);
1439 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1441 pwm->tls_verify = 0;
1442 rc = GPG_ERR_INV_VALUE;
1444 break;
1445 case PWMD_OPTION_SOCKET_TIMEOUT:
1446 pwm->socket_timeout = va_arg (ap, int);
1447 if (pwm->socket_timeout < 0)
1449 pwm->socket_timeout = 0;
1450 rc = GPG_ERR_INV_VALUE;
1453 #ifdef WITH_SSH
1454 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1456 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1457 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1458 pwm->socket_timeout * 1000);
1460 #endif
1461 #ifdef WITH_GNUTLS
1462 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1463 pwm->tcp->tls->timeout = pwm->socket_timeout;
1464 #endif
1465 break;
1466 case PWMD_OPTION_OVERRIDE_INQUIRE:
1467 pwm->override_inquire = va_arg (ap, int);
1469 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1471 pwm->override_inquire = 0;
1472 rc = GPG_ERR_INV_VALUE;
1474 break;
1475 default:
1476 rc = GPG_ERR_UNKNOWN_OPTION;
1477 break;
1480 va_end (ap);
1481 return FINISH (rc);
1484 gpg_error_t
1485 pwmd_new (const char *name, pwm_t ** pwm)
1487 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1488 gpg_error_t rc;
1490 if (!h)
1491 return FINISH (GPG_ERR_ENOMEM);
1493 if (name)
1495 h->name = pwmd_strdup (name);
1496 if (!h->name)
1498 pwmd_free (h);
1499 return FINISH (GPG_ERR_ENOMEM);
1503 reset_handle (h);
1504 h->pinentry_timeout = -30;
1505 h->pinentry_tries = 3;
1506 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1507 h->prot = PWMD_IP_ANY;
1508 #endif
1510 if (ttyname (STDOUT_FILENO))
1512 char buf[256];
1514 ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
1515 h->pinentry_tty = pwmd_strdup (buf);
1516 if (!h->pinentry_tty)
1518 rc = GPG_ERR_ENOMEM;
1519 goto fail;
1523 if (getenv ("TERM") && h->pinentry_tty)
1525 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
1526 if (!h->pinentry_term)
1528 rc = GPG_ERR_ENOMEM;
1529 goto fail;
1533 if (getenv ("DISPLAY"))
1535 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
1536 if (!h->pinentry_display)
1538 rc = GPG_ERR_ENOMEM;
1539 goto fail;
1543 update_pinentry_settings (h);
1544 *pwm = h;
1545 return 0;
1547 fail:
1548 pwmd_close (h);
1549 return FINISH (rc);
1552 void
1553 pwmd_free (void *ptr)
1555 _xfree (ptr);
1558 void *
1559 pwmd_malloc (size_t size)
1561 return _xmalloc (size);
1564 void *
1565 pwmd_calloc (size_t nmemb, size_t size)
1567 return _xcalloc (nmemb, size);
1570 void *
1571 pwmd_realloc (void *ptr, size_t size)
1573 return _xrealloc (ptr, size);
1576 char *
1577 pwmd_strdup (const char *str)
1579 char *t;
1580 size_t len;
1581 register size_t c;
1583 len = strlen (str);
1584 t = _xmalloc ((len + 1) * sizeof (char));
1585 if (!t)
1586 return NULL;
1588 for (c = 0; c < len; c++)
1589 t[c] = str[c];
1591 t[c] = 0;
1592 return t;
1595 char *
1596 pwmd_strdup_printf (const char *fmt, ...)
1598 va_list ap, ap2;
1599 int len;
1600 char *buf;
1602 if (!fmt)
1603 return NULL;
1605 va_start (ap, fmt);
1606 va_copy (ap2, ap);
1607 len = vsnprintf (NULL, 0, fmt, ap);
1608 va_end (ap);
1609 buf = pwmd_malloc (++len);
1610 if (buf)
1611 vsnprintf (buf, len, fmt, ap2);
1613 va_end (ap2);
1614 return buf;
1617 gpg_error_t
1618 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
1619 size_t * len, pwmd_pinentry_t which)
1621 #ifndef WITH_PINENTRY
1622 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
1623 #else
1624 gpg_error_t rc = _pwmd_getpin (pwm, filename, result, len, which);
1626 return FINISH (rc);
1627 #endif
1630 const char *
1631 pwmd_version ()
1633 return LIBPWMD_VERSION_STR;
1636 unsigned int
1637 pwmd_features ()
1639 unsigned int n = 0;
1641 #ifdef WITH_PINENTRY
1642 n |= PWMD_FEATURE_PINENTRY;
1643 #endif
1644 #ifdef WITH_SSH
1645 n |= PWMD_FEATURE_SSH;
1646 #endif
1647 #ifdef WITH_QUALITY
1648 n |= PWMD_FEATURE_CRACK;
1649 #endif
1650 #ifdef WITH_GNUTLS
1651 n |= PWMD_FEATURE_GNUTLS;
1652 #endif
1653 return n;
1656 gpg_error_t
1657 pwmd_fd (pwm_t * pwm, int *fd)
1659 if (!pwm || !fd)
1660 return FINISH (GPG_ERR_INV_ARG);
1662 if (pwm->fd == -1)
1663 return FINISH (GPG_ERR_INV_STATE);
1665 *fd = pwm->fd;
1666 return 0;