Add PWMD_OPTION_SSH_PASSPHRASE.
[libpwmd.git] / src / libpwmd.c
blob5fbf0eedc6db57c9b46bcdda40b173d6fb48d114
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <signal.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <sys/wait.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <time.h>
42 #include <limits.h>
43 #include <sys/select.h>
44 #include <termios.h>
45 #include <libpwmd.h>
47 #ifdef HAVE_STRINGS_H
48 #include <strings.h>
49 #endif
51 #ifndef LINE_MAX
52 #define LINE_MAX 2048
53 #endif
55 #include "mem.h"
56 #include "misc.h"
57 #include "types.h"
59 #ifdef WITH_PINENTRY
60 #include "pinentry.h"
61 #endif
63 #ifdef WITH_QUALITY
64 #include "zxcvbn.h"
65 #endif
67 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
68 #include <sys/types.h>
69 #include <sys/socket.h>
70 #include <netdb.h>
71 #include <netinet/in.h>
72 #endif
74 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
75 ? gpg_error(rc) : rc
77 typedef struct
79 size_t len;
80 void *buf;
81 } membuf_t;
83 ssize_t
84 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
86 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
87 pwm_t *pwm = assuan_get_pointer (ctx);
89 #ifdef WITH_SSH
90 if (pwm && pwm->tcp && pwm->tcp->ssh)
91 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
92 #endif
93 #ifdef WITH_GNUTLS
94 if (pwm && pwm->tcp && pwm->tcp->tls)
95 return read_hook_tls (pwm, fd, data, len);
96 #endif
97 #endif
99 return read ((int) fd, data, len);
102 ssize_t
103 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
104 size_t len)
106 ssize_t wrote;
107 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
108 pwm_t *pwm = assuan_get_pointer (ctx);
110 #ifdef WITH_SSH
111 if (pwm && pwm->tcp && pwm->tcp->ssh)
112 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
113 #endif
114 #ifdef WITH_GNUTLS
115 if (pwm && pwm->tcp && pwm->tcp->tls)
116 return write_hook_tls (pwm, fd, data, len);
117 #endif
118 #endif
120 /* libassuan cannot handle EAGAIN when doing writes. */
123 wrote = write ((int) fd, data, len);
124 if (wrote == -1 && errno == EAGAIN)
125 usleep (50000);
127 while (wrote == -1 && errno == EAGAIN);
129 return wrote;
132 pid_t
133 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
134 int options)
136 return waitpid (pid, status, options);
139 gpg_error_t
140 pwmd_init ()
142 static int initialized;
144 #ifdef WITH_GNUTLS
145 // May be called more than once.
146 gnutls_global_init ();
147 #endif
149 if (initialized)
150 return 0;
152 #ifdef ENABLE_NLS
153 bindtextdomain ("libpwmd", LOCALEDIR);
154 #endif
155 #ifdef WITH_SSH
156 libssh2_init (0);
157 #endif
158 gpgrt_init ();
159 gpgrt_set_alloc_func (_xrealloc_gpgrt);
161 #ifdef WITH_QUALITY
162 ZxcvbnInit (NULL);
163 #endif
165 initialized = 1;
166 return 0;
169 void
170 pwmd_deinit ()
172 #ifdef WITH_GNUTLS
173 gnutls_global_deinit ();
174 #endif
175 #ifdef WITH_QUALITY
176 ZxcvbnUnInit();
177 #endif
180 gpg_error_t
181 _connect_finalize (pwm_t * pwm)
183 gpg_error_t rc = 0;
184 char *result = NULL;
185 int active[2];
186 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
188 if (n <= 0)
189 return GPG_ERR_EBADFD;
191 pwm->fd = active[0];
192 #ifdef WITH_PINENTRY
193 pwm->pinentry_pid = -1;
194 #endif
196 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "GETINFO VERSION");
197 if (!rc)
199 pwm->version = strtoul (result, NULL, 16);
200 pwmd_free (result);
203 if (!rc && pwm->name)
204 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
205 pwm->name);
207 return rc;
210 static gpg_error_t
211 connect_uds (pwm_t * pwm, const char *path)
213 char *socketpath = NULL;
214 struct passwd pw;
215 char *pwbuf;
216 gpg_error_t rc;
218 if (!pwm)
219 return GPG_ERR_INV_ARG;
221 pwbuf = _getpwuid (&pw);
222 if (!pwbuf)
223 return gpg_error_from_syserror ();
225 if (!path || !*path)
226 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
227 else
228 socketpath = _expand_homedir ((char *) path, &pw);
230 pwmd_free (pwbuf);
231 if (!socketpath)
232 return GPG_ERR_ENOMEM;
234 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
235 pwmd_free (socketpath);
236 return rc ? rc : _connect_finalize (pwm);
239 static gpg_error_t
240 init_handle (pwm_t * pwm)
242 gpg_error_t rc;
243 static struct assuan_malloc_hooks mhooks = {
244 pwmd_malloc, pwmd_realloc, pwmd_free
246 static struct assuan_system_hooks shooks = {
247 ASSUAN_SYSTEM_HOOKS_VERSION,
248 __assuan_usleep,
249 __assuan_pipe,
250 __assuan_close,
251 hook_read,
252 hook_write,
253 //FIXME
254 NULL, //recvmsg
255 NULL, //sendmsg both are used for FD passing
256 __assuan_spawn,
257 hook_waitpid,
258 __assuan_socketpair,
259 __assuan_socket,
260 __assuan_connect
263 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
264 NULL);
265 if (rc)
266 return rc;
268 assuan_set_pointer (pwm->ctx, pwm);
269 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
270 return 0;
273 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
274 void
275 free_tcp (pwm_t *pwm)
277 struct tcp_s *tcp = pwm->tcp;
279 if (!tcp)
280 return;
282 #ifdef WITH_SSH
283 _free_ssh_conn (tcp->ssh);
284 #endif
285 #ifdef WITH_GNUTLS
286 tls_free (pwm);
287 #endif
289 pwmd_free (tcp->host);
290 if (tcp->addrs)
292 freeaddrinfo (tcp->addrs);
293 tcp->addrs = NULL;
296 pthread_cond_destroy (&tcp->dns_cond);
297 pthread_mutex_destroy (&tcp->dns_mutex);
298 pwmd_free (tcp);
299 pwm->tcp = NULL;
301 #endif
303 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
304 static void *
305 resolve_host_thread (void *arg)
307 pwm_t *pwm = arg;
308 struct addrinfo hints = { 0 };
309 char portstr[6];
311 switch (pwm->prot)
313 case PWMD_IP_ANY:
314 hints.ai_family = AF_UNSPEC;
315 break;
316 case PWMD_IPV4:
317 hints.ai_family = AF_INET;
318 break;
319 case PWMD_IPV6:
320 hints.ai_family = AF_INET6;
321 break;
324 hints.ai_socktype = SOCK_STREAM;
325 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
326 int *n = pwmd_malloc (sizeof (int));
327 pthread_cleanup_push (pwmd_free, n);
328 *n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
329 pthread_cleanup_pop (0);
330 pthread_cond_broadcast (&pwm->tcp->dns_cond);
331 pthread_exit (n);
332 return NULL;
335 gpg_error_t
336 tcp_connect_common (pwm_t * pwm)
338 #define TS_TIMEOUT 50000000L
339 int n;
340 gpg_error_t rc = 0;
341 pthread_t tid;
342 time_t now;
344 time (&now);
345 n = pthread_create (&tid, NULL, resolve_host_thread, pwm);
346 if (n)
347 return gpg_error_from_errno (n);
349 pthread_mutex_lock (&pwm->tcp->dns_mutex);
351 for (;;)
353 struct timespec ts;
354 int *result = NULL;
356 clock_gettime (CLOCK_REALTIME, &ts);
357 if (ts.tv_nsec + TS_TIMEOUT >= 1000000000LL) {
358 ts.tv_sec++;
359 ts.tv_nsec = 0;
361 else
362 ts.tv_nsec += TS_TIMEOUT;
364 if (pwm->cancel)
366 #ifdef HAVE_PTHREAD_CANCEL
367 pthread_cancel (tid);
368 pthread_join (tid, NULL);
369 #else
370 pthread_join (tid, (void **)&result);
371 pwmd_free (result);
372 #endif
373 return GPG_ERR_CANCELED;
376 n = pthread_cond_timedwait (&pwm->tcp->dns_cond, &pwm->tcp->dns_mutex,
377 &ts);
378 if (n == ETIMEDOUT)
380 if (pwm->socket_timeout && ts.tv_sec - now >= pwm->socket_timeout)
382 #ifdef HAVE_PTHREAD_CANCEL
383 pthread_cancel (tid);
384 pthread_join (tid, NULL);
385 #else
386 pthread_join (tid, (void **)&result);
387 pwmd_free (result);
388 #endif
389 return GPG_ERR_ETIMEDOUT;
392 continue;
394 else if (n)
396 #ifdef HAVE_PTHREAD_CANCEL
397 pthread_cancel (tid);
398 pthread_join (tid, NULL);
399 #else
400 pthread_join (tid, (void **)&result);
401 pwmd_free (result);
402 #endif
403 return gpg_error_from_errno (n);
406 pthread_join (tid, (void **)&result);
407 n = *result;
408 pwmd_free (result);
409 break;
412 if (n)
413 return GPG_ERR_UNKNOWN_HOST; //FIXME
415 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
416 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
418 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
419 if (pwm->fd == -1)
421 rc = gpg_error_from_syserror ();
422 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
423 break;
424 continue;
427 if (fcntl (pwm->fd, F_SETFL, O_NONBLOCK) == -1)
429 rc = gpg_error_from_syserror ();
430 break;
433 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
434 pwm->tcp->addr->ai_family == AF_INET6
435 ? sizeof (struct sockaddr_in6)
436 : sizeof (struct sockaddr)) == -1)
438 int n;
439 struct timeval tv;
440 fd_set wfds;
441 unsigned elapsed = 0;
443 rc = gpg_error_from_syserror ();
444 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
446 close (pwm->fd);
447 pwm->fd = -1;
448 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
449 return rc;
450 continue;
453 again:
454 tv.tv_sec = 1;
455 tv.tv_usec = 0;
456 FD_ZERO (&wfds);
457 FD_SET (pwm->fd, &wfds);
458 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
459 rc = 0;
460 if (!n || pwm->cancel)
462 if (pwm->cancel)
463 rc = gpg_error (GPG_ERR_CANCELED);
464 else if (++elapsed >= pwm->socket_timeout)
465 rc = gpg_error (GPG_ERR_ETIMEDOUT);
466 else
467 goto again;
469 else if (n != -1)
471 socklen_t len = sizeof(int);
473 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
474 if (n)
475 rc = gpg_error_from_errno (n);
477 else if (n == -1)
478 rc = gpg_error_from_syserror ();
480 if (rc)
482 close (pwm->fd);
483 pwm->fd = -1;
484 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
485 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
486 || pwm->cancel)
487 return rc;
489 else
490 break;
492 else
493 break;
496 if (!rc)
497 if (fcntl (pwm->fd, F_SETFL, 0) == -1)
498 rc = gpg_error_from_syserror ();
500 return rc;
502 #endif
504 static void
505 command_start (pwm_t *pwm)
507 pwm->cancel = 0;
510 gpg_error_t
511 pwmd_connect (pwm_t * pwm, const char *url, ...)
513 const char *p = url;
514 gpg_error_t rc;
516 if (!pwm)
517 return FINISH (GPG_ERR_INV_ARG);
518 else if (!pwm->ctx)
520 rc = init_handle (pwm);
521 if (rc)
522 return rc;
525 command_start (pwm);
527 if (!(pwm->opts & OPT_SIGPIPE))
528 signal (SIGPIPE, SIG_IGN);
530 #ifdef WITH_GNUTLS
531 pwm->tls_error = 0;
532 #endif
533 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
535 if (p && (*p == '/' || *p == '~'))
536 rc = connect_uds (pwm, p);
537 else if (!p || !strncmp (p, "file://", 7))
539 if (p)
540 p += 7;
541 #ifdef DEFAULT_PWMD_SOCKET
542 else
543 p = DEFAULT_PWMD_SOCKET;
544 #endif
545 rc = connect_uds (pwm, p);
547 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
548 !strncmp (p, "ssh4://", 7))
550 #ifndef WITH_SSH
551 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
552 #else
553 char *host = NULL;
554 int port;
555 char *username = NULL;
557 if (!strncmp (p, "ssh6://", 7))
559 pwm->prot = PWMD_IPV6;
560 p += 7;
562 else if (!strncmp (p, "ssh4://", 7))
564 pwm->prot = PWMD_IPV4;
565 p += 7;
567 else
569 pwm->prot = PWMD_IP_ANY;
570 p += 6;
573 rc = _parse_ssh_url (p, &host, &port, &username);
574 if (!rc)
576 va_list ap;
577 char *identity = NULL;
578 char *knownhosts = NULL;
580 va_start (ap, url);
581 identity = va_arg (ap, char *);
583 if (!identity && !pwm->use_agent)
584 rc = GPG_ERR_INV_ARG;
585 else
586 knownhosts = va_arg (ap, char *);
588 va_end (ap);
590 if (!rc)
591 rc = _do_ssh_connect (pwm, host, port, identity, username,
592 knownhosts);
593 if (!rc)
595 rc = _connect_finalize (pwm);
596 if (rc)
597 free_tcp (pwm);
601 pwmd_free (host);
602 pwmd_free (username);
603 pwm->local_pinentry = 1;
604 pwmd_free (pwm->ssh_passphrase);
605 pwm->ssh_passphrase = NULL;
606 #endif
608 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
609 !strncmp (p, "tls4://", 7))
611 #ifndef WITH_GNUTLS
612 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
613 #else
614 char *host = NULL;
615 int port;
617 if (!strncmp (p, "tls6://", 7))
619 pwm->prot = PWMD_IPV6;
620 p += 7;
622 else if (!strncmp (p, "tls4://", 7))
624 pwm->prot = PWMD_IPV4;
625 p += 7;
627 else
629 pwm->prot = PWMD_IP_ANY;
630 p += 6;
633 rc = _parse_tls_url (p, &host, &port);
634 if (!rc)
636 va_list ap;
637 char *clientcert = NULL;
638 char *clientkey = NULL;
639 char *cacert = NULL;
640 char *prio = NULL;
641 char *server_fp = NULL;
643 va_start (ap, url);
644 clientcert = va_arg (ap, char *);
646 if (!clientcert)
647 rc = GPG_ERR_INV_ARG;
648 else
650 clientkey = va_arg (ap, char *);
651 if (!clientkey)
652 rc = GPG_ERR_INV_ARG;
653 else
655 cacert = va_arg (ap, char *);
656 if (!cacert)
657 rc = GPG_ERR_INV_ARG;
658 else
660 prio = va_arg (ap, char *);
661 server_fp = va_arg (ap, char *);
666 va_end (ap);
668 if (!rc)
669 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
670 cacert, prio, server_fp, pwm->tls_verify);
671 if (!rc)
673 rc = _connect_finalize (pwm);
674 if (rc)
675 free_tcp (pwm);
679 pwmd_free (host);
680 pwm->local_pinentry = 1;
681 #endif
684 if (!rc)
685 pwm->connected = 1;
687 return FINISH (rc);
690 static void
691 disconnect (pwm_t * pwm)
693 if (!pwm)
694 return;
696 if (pwm->ctx)
697 assuan_release (pwm->ctx);
699 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
700 free_tcp (pwm);
701 #endif
702 pwm->ctx = NULL;
703 pwm->fd = -1;
704 pwm->connected = 0;
707 void
708 pwmd_close (pwm_t * pwm)
710 if (!pwm)
711 return;
713 disconnect (pwm);
714 pwmd_free (pwm->pinentry_error);
715 pwmd_free (pwm->pinentry_desc);
716 pwmd_free (pwm->pinentry_prompt);
717 pwmd_free (pwm->pinentry_tty);
718 pwmd_free (pwm->pinentry_display);
719 pwmd_free (pwm->pinentry_term);
720 pwmd_free (pwm->pinentry_lcctype);
721 pwmd_free (pwm->pinentry_lcmessages);
722 pwmd_free (pwm->filename);
723 pwmd_free (pwm->name);
724 pwmd_free (pwm->passphrase_info);
725 pwmd_free (pwm->passphrase_hint);
726 pwmd_free (pwm->ssh_passphrase);
728 #ifdef WITH_PINENTRY
729 if (pwm->pctx)
730 _pinentry_disconnect (pwm);
731 #endif
733 pwmd_free (pwm);
736 static gpg_error_t
737 inquire_realloc_cb (void *data, const void *buffer, size_t len)
739 membuf_t *mem = (membuf_t *) data;
740 void *p;
742 if (!buffer)
743 return 0;
745 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
746 return gpg_error (GPG_ERR_ENOMEM);
748 mem->buf = p;
749 memcpy ((char *) mem->buf + mem->len, buffer, len);
750 mem->len += len;
751 return 0;
754 static gpg_error_t
755 get_password (pwm_t * pwm, char **result, size_t * len,
756 pwmd_pinentry_t w, int echo)
758 char buf[ASSUAN_LINELENGTH+1] = { 0 }, *p;
759 struct termios told, tnew;
760 char *key = NULL;
762 if (result)
763 *result = NULL;
765 if (len)
766 *len = 0;
768 if (!isatty (STDIN_FILENO))
770 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
771 return GPG_ERR_ENOTTY;
774 if (!echo)
776 if (tcgetattr (STDIN_FILENO, &told) == -1)
777 return gpg_error_from_syserror ();
779 memcpy (&tnew, &told, sizeof (struct termios));
780 tnew.c_lflag &= ~(ECHO);
781 tnew.c_lflag |= ICANON | ECHONL;
783 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
785 int n = errno;
787 tcsetattr (STDIN_FILENO, TCSANOW, &told);
788 return gpg_error_from_errno (n);
792 if (pwm->passphrase_hint)
793 fprintf(stderr, N_("Key info: %s\n"), pwm->passphrase_hint);
795 switch (w)
797 case PWMD_PINENTRY_OPEN:
798 fprintf (stderr, N_("Passphrase for %s: "), pwm->filename);
799 break;
800 case PWMD_PINENTRY_OPEN_FAILED:
801 fprintf (stderr, N_("Invalid passphrase. Passphrase for %s: "),
802 pwm->filename);
803 break;
804 case PWMD_PINENTRY_SAVE:
805 fprintf (stderr, N_("New passphrase for %s: "), pwm->filename);
806 break;
807 case PWMD_PINENTRY_SAVE_CONFIRM:
808 fprintf (stderr, N_("Repeat passphrase: "));
809 break;
810 case PWMD_PINENTRY_CONFIRM:
811 if (pwm->pinentry_desc)
812 fprintf (stderr, "%s", pwm->pinentry_desc);
814 if (pwm->pinentry_prompt)
815 fprintf (stderr, "%s", pwm->pinentry_prompt);
816 else
817 fprintf(stderr, N_("Confirm [y/N]:"));
818 default:
819 break;
822 p = fgets (buf, sizeof (buf), stdin);
824 if (!echo)
825 tcsetattr (STDIN_FILENO, TCSANOW, &told);
827 if (!p || feof (stdin))
829 clearerr (stdin);
830 return GPG_ERR_CANCELED;
833 /* Strip the newline character. */
834 p[strlen (p) - 1] = 0;
836 if (buf[0])
838 if (w == PWMD_PINENTRY_CONFIRM)
840 if (*p != 'y' && *p != 'Y')
841 return GPG_ERR_CANCELED;
842 return 0;
845 key = pwmd_strdup_printf ("%s", p);
846 wipememory (buf, 0, sizeof (buf));
847 if (!key)
848 return GPG_ERR_ENOMEM;
850 if (result)
851 *result = key;
853 if (len)
854 *len = strlen (key);
856 else
858 if (w == PWMD_PINENTRY_CONFIRM)
859 return GPG_ERR_CANCELED;
861 /* To satisfy inquire_cb(). */
862 if (result)
863 *result = pwmd_strdup ("");
865 if (len)
866 *len = 1;
869 return 0;
872 gpg_error_t
873 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
875 gpg_error_t rc;
876 int new_password = 0;
877 char *password = NULL, *newpass = NULL;
878 int error = 0;
880 command_start (pwm);
882 if (data)
883 *data = NULL;
885 if (size)
886 *size = 0;
888 if (!strcmp (keyword, "NEW_PASSPHRASE"))
889 new_password = 1;
891 if (!new_password && pwm->pinentry_try)
892 error = 1;
894 again:
895 if (pwm->disable_pinentry)
897 rc = get_password (pwm, &password, size,
898 new_password ? PWMD_PINENTRY_SAVE :
899 error ? PWMD_PINENTRY_OPEN_FAILED :
900 PWMD_PINENTRY_OPEN, 0);
901 if (!rc && new_password)
902 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
905 else
907 pwmd_pinentry_t which;
909 if (error)
910 which = new_password
911 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
912 else
913 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
915 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
916 if (!rc && new_password)
917 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
918 PWMD_PINENTRY_SAVE_CONFIRM);
921 if (!rc && new_password)
923 if ((!password && newpass) || (!newpass && password)
924 || (newpass && password && strcmp (newpass, password)))
926 if (pwm->disable_pinentry)
927 fprintf (stderr, N_("Passphrases do not match.\n"));
929 pwmd_free (password);
930 pwmd_free (newpass);
931 password = newpass = NULL;
932 error = 1;
933 goto again;
937 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
938 pwmd_free (newpass);
939 if (!rc && data)
940 *data = password;
941 else
942 pwmd_free (password);
944 return rc;
947 static gpg_error_t
948 inquire_cb (void *data, const char *keyword)
950 pwm_t *pwm = (pwm_t *) data;
951 gpg_error_t rc = 0;
952 int free_result = 0;
953 char *result = NULL;
954 int is_password = 0;
955 int new_password = 0;
957 if (!strcmp (keyword, "PASSPHRASE") || !strcmp (keyword, "SIGN_PASSPHRASE"))
958 is_password = 1;
959 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
960 new_password = 1;
962 /* Shouldn't get this far without a callback. */
963 if (!pwm->override_inquire && !pwm->inquire_func
964 && !is_password && !new_password)
965 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
967 for (;;)
969 size_t len = 0;
970 gpg_error_t arc;
972 result = NULL;
974 if (!pwm->override_inquire && (is_password || new_password))
976 free_result = 1;
977 rc = pwmd_password (data, keyword, &result, &len);
978 if (!rc)
979 rc = GPG_ERR_EOF;
981 else
982 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
983 &len);
985 /* gpg will truncate a passphrase at the first nil byte which may be bad
986 * for generated key files. */
987 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
988 && (is_password || new_password))
990 if (len && result && *result)
992 for (size_t n = 0; n < len; n++)
994 if (result[n] == 0 && n+1 != len)
995 rc = GPG_ERR_INV_PASSPHRASE;
1000 cancel:
1001 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
1003 #ifndef LIBASSUAN_2_1_0
1004 gpg_error_t trc = rc;
1006 /* Cancel this inquire. */
1007 rc = assuan_send_data (pwm->ctx, NULL, 1);
1008 if (!rc)
1010 char *line;
1011 size_t len;
1013 /* There is a bug (or feature?) in assuan_send_data() that
1014 * when cancelling an inquire the next read from the server is
1015 * not done until the next command making the next command
1016 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
1018 rc = assuan_read_line (pwm->ctx, &line, &len);
1020 /* Restore the original error. This differs from the error
1021 * returned from the pwmd command (GPG_ERR_CANCELED). This
1022 * error is returned to the calling function.
1024 if (!rc)
1025 rc = trc;
1027 #endif
1028 break;
1031 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
1033 if (len <= 0 && !result)
1035 rc = 0;
1036 break;
1038 else if ((len <= 0 && result) || (len && !result))
1040 rc = gpg_error (GPG_ERR_INV_ARG);
1041 break;
1044 if (pwm->inquire_maxlen
1045 && pwm->inquire_sent + len > pwm->inquire_maxlen)
1047 rc = gpg_error (GPG_ERR_TOO_LARGE);
1048 if (!free_result)
1049 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
1050 &result, &len);
1051 goto cancel;
1054 arc = assuan_send_data (pwm->ctx, result, len);
1055 if (gpg_err_code (rc) == GPG_ERR_EOF)
1057 rc = arc;
1058 break;
1061 rc = arc;
1063 else if (rc)
1064 break;
1066 if (!rc)
1068 pwm->inquire_sent += len;
1070 if (pwm->status_func)
1072 char buf[ASSUAN_LINELENGTH];
1074 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
1075 pwm->inquire_total);
1076 rc = pwm->status_func (pwm->status_data, buf);
1077 if (rc)
1078 continue;
1083 if (free_result)
1084 pwmd_free (result);
1086 pwm->inquire_maxlen = pwm->inquire_sent = 0;
1087 return rc;
1090 static gpg_error_t
1091 parse_assuan_line (pwm_t * pwm)
1093 gpg_error_t rc;
1094 char *line;
1095 size_t len;
1097 rc = assuan_read_line (pwm->ctx, &line, &len);
1098 if (!rc)
1100 if (line[0] == 'O' && line[1] == 'K' &&
1101 (line[2] == 0 || line[2] == ' '))
1104 else if (line[0] == '#')
1107 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
1109 if (pwm->status_func)
1111 rc = pwm->status_func (pwm->status_data,
1112 line[1] == 0 ? line + 1 : line + 2);
1115 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
1116 (line[3] == 0 || line[3] == ' '))
1118 line += 4;
1119 rc = strtol (line, NULL, 10);
1123 return rc;
1126 static void
1127 reset_handle (pwm_t *pwm)
1129 pwm->fd = -1;
1130 pwm->cancel = 0;
1131 pwm->pinentry_disabled = 0;
1132 #ifdef WITH_PINENTRY
1133 if (pwm->pctx)
1134 _pinentry_disconnect (pwm);
1135 #endif
1136 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1137 #ifdef WITH_GNUTLS
1138 pwm->tls_error = 0;
1139 #endif
1141 if (pwm->tcp)
1142 pwm->tcp->rc = 0;
1143 #endif
1146 gpg_error_t
1147 pwmd_disconnect (pwm_t * pwm)
1149 if (!pwm)
1150 return FINISH (GPG_ERR_INV_ARG);
1152 command_start (pwm);
1154 if (pwm->fd == -1)
1155 return FINISH (GPG_ERR_INV_STATE);
1157 disconnect (pwm);
1158 reset_handle (pwm);
1159 return 0;
1162 /* Note that this should only be called when not in a command. */
1163 gpg_error_t
1164 pwmd_process (pwm_t * pwm)
1166 gpg_error_t rc = 0;
1167 fd_set fds;
1168 struct timeval tv = { 0, 0 };
1169 int n;
1171 if (!pwm || pwm->fd == -1)
1172 return FINISH (GPG_ERR_INV_ARG);
1173 else if (!pwm->ctx)
1174 return FINISH (GPG_ERR_INV_STATE);
1176 FD_ZERO (&fds);
1177 FD_SET (pwm->fd, &fds);
1178 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1180 if (n == -1)
1181 return FINISH (gpg_error_from_syserror ());
1183 if (n > 0)
1185 if (FD_ISSET (pwm->fd, &fds))
1186 rc = parse_assuan_line (pwm);
1189 while (!rc && assuan_pending_line (pwm->ctx))
1190 rc = parse_assuan_line (pwm);
1192 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1193 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1195 close (pwm->fd);
1196 pwm->fd = -1;
1198 #endif
1200 return FINISH (rc);
1203 static gpg_error_t
1204 status_cb (void *data, const char *line)
1206 pwm_t *pwm = data;
1208 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1209 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1210 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1212 pwmd_free (pwm->passphrase_hint);
1213 pwm->passphrase_hint = pwmd_strdup (line+16);
1215 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1217 pwmd_free (pwm->passphrase_info);
1218 pwm->passphrase_info = pwmd_strdup (line+16);
1221 if (pwm->status_func)
1222 return pwm->status_func (pwm->status_data, line);
1224 return 0;
1227 gpg_error_t
1228 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1229 char **result, size_t * len, const char *cmd)
1231 membuf_t data;
1232 gpg_error_t rc;
1234 if (!cmd || !*cmd)
1235 return FINISH (GPG_ERR_INV_ARG);
1237 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1238 return FINISH (GPG_ERR_LINE_TOO_LONG);
1240 data.len = 0;
1241 data.buf = NULL;
1242 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1243 #ifdef WITH_QUALITY
1244 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1245 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1246 #else
1247 inquire_cb, pwm,
1248 #endif
1249 status_cb, pwm);
1251 if (rc)
1253 if (data.buf)
1255 pwmd_free (data.buf);
1256 data.buf = NULL;
1259 else
1261 if (data.buf)
1263 inquire_realloc_cb (&data, "", 1);
1265 if (result)
1266 *result = (char *) data.buf;
1267 else
1268 pwmd_free (data.buf);
1270 if (len)
1271 *len = data.len;
1275 pwm->inquire_maxlen = 0;
1276 return rc;
1279 gpg_error_t
1280 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1281 pwmd_inquire_cb_t func, void *user, const char *cmd,
1282 va_list ap)
1284 char *buf;
1285 size_t len;
1286 va_list ap2;
1288 command_start (pwm);
1290 if (result)
1291 *result = NULL;
1293 if (rlen)
1294 *rlen = 0;
1296 if (!pwm || !cmd)
1297 return FINISH (GPG_ERR_INV_ARG);
1298 if (!pwm->ctx)
1299 return FINISH (GPG_ERR_INV_STATE);
1302 * C99 allows the dst pointer to be null which will calculate the length
1303 * of the would-be result and return it.
1305 va_copy (ap2, ap);
1306 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1307 buf = (char *) pwmd_malloc (len);
1308 if (!buf)
1310 va_end (ap2);
1311 return FINISH (GPG_ERR_ENOMEM);
1314 len = vsnprintf (buf, len, cmd, ap2);
1315 va_end (ap2);
1317 if (buf[strlen (buf) - 1] == '\n')
1318 buf[strlen (buf) - 1] = 0;
1319 if (buf[strlen (buf) - 1] == '\r')
1320 buf[strlen (buf) - 1] = 0;
1322 pwm->inquire_func = func;
1323 pwm->inquire_data = user;
1324 pwm->inquire_sent = 0;
1325 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1326 pwmd_free (buf);
1327 return rc;
1330 gpg_error_t
1331 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1332 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1334 va_list ap;
1336 if (result)
1337 *result = NULL;
1339 if (len)
1340 *len = 0;
1342 if (!pwm || !cmd)
1343 return FINISH (GPG_ERR_INV_ARG);
1344 if (!pwm->ctx)
1345 return FINISH (GPG_ERR_INV_STATE);
1347 va_start (ap, cmd);
1348 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1349 va_end (ap);
1350 return rc;
1353 static gpg_error_t
1354 send_pinentry_timeout (pwm_t *pwm)
1356 gpg_error_t rc = 0;
1358 if ((pwm->pinentry_timeout >= 0
1359 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1360 || (pwm->pinentry_timeout == -1
1361 && pwm->pinentry_timeout != pwm->current_pinentry_timeout))
1363 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1364 "OPTION pinentry-timeout=%i",
1365 pwm->pinentry_timeout);
1366 if (!rc)
1367 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1370 return rc;
1373 static gpg_error_t
1374 send_pinentry_options (pwm_t * pwm)
1376 gpg_error_t rc;
1378 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1379 "OPTION disable-pinentry=0");
1380 if (!rc && pwm->pinentry_tty)
1381 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1382 pwm->pinentry_tty);
1384 if (!rc && pwm->pinentry_term)
1385 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1386 pwm->pinentry_term);
1388 if (!rc && pwm->pinentry_display)
1389 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1390 pwm->pinentry_display);
1392 if (!rc && pwm->pinentry_desc)
1393 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1394 pwm->pinentry_desc);
1396 if (!rc && pwm->pinentry_lcctype)
1397 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1398 pwm->pinentry_lcctype);
1400 if (!rc && pwm->pinentry_lcmessages)
1401 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1402 pwm->pinentry_lcmessages);
1404 if (!rc)
1405 rc = send_pinentry_timeout (pwm);
1407 return rc;
1410 gpg_error_t
1411 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1413 if (!pwm || !result)
1414 return FINISH (GPG_ERR_INV_ARG);
1416 *result = PWMD_SOCKET_LOCAL;
1418 if (pwm->fd == -1)
1419 return FINISH (GPG_ERR_INV_STATE);
1421 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1422 #ifdef WITH_SSH
1423 if (pwm->tcp && pwm->tcp->ssh)
1424 *result = PWMD_SOCKET_SSH;
1425 #endif
1426 #ifdef WITH_GNUTLS
1427 if (pwm->tcp && pwm->tcp->tls)
1428 *result = PWMD_SOCKET_TLS;
1429 #endif
1430 #endif
1431 return 0;
1434 static gpg_error_t
1435 disable_pinentry (pwm_t *pwm, int *disable)
1437 gpg_error_t rc;
1438 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1439 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1440 #else
1441 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1442 #endif
1444 if (disable)
1445 *disable = no_pinentry;
1447 if (pwm->pinentry_disabled && no_pinentry)
1448 return 0;
1449 else if (!pwm->pinentry_disabled && !no_pinentry)
1450 return 0;
1452 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1453 no_pinentry);
1454 if (!rc)
1455 pwm->pinentry_disabled = no_pinentry;
1457 return rc;
1460 gpg_error_t
1461 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1462 void *data)
1464 gpg_error_t rc = 0;
1465 int no_pinentry = 0;
1467 if (!pwm || !filename || !*filename)
1468 return FINISH (GPG_ERR_INV_ARG);
1470 if (!pwm->ctx)
1471 return FINISH (GPG_ERR_INV_STATE);
1473 command_start (pwm);
1474 rc = disable_pinentry (pwm, &no_pinentry);
1475 if (!rc && !no_pinentry)
1476 rc = send_pinentry_options (pwm);
1478 if (!rc)
1480 pwm->pinentry_try = 0;
1481 pwmd_free (pwm->filename);
1482 pwm->filename = pwmd_strdup (filename);
1486 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1487 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1488 filename);
1490 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1491 && pwm->pinentry_disabled
1492 && ++pwm->pinentry_try < pwm->pinentry_tries);
1494 pwm->pinentry_try = 0;
1496 if (rc)
1498 pwmd_free (pwm->filename);
1499 pwm->filename = NULL;
1503 pwmd_free (pwm->passphrase_hint);
1504 pwmd_free (pwm->passphrase_info);
1505 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1506 return FINISH (rc);
1509 static gpg_error_t
1510 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1511 void *data, int save)
1513 gpg_error_t rc = 0;
1514 int no_pinentry = 0;
1516 if (!pwm)
1517 return FINISH (GPG_ERR_INV_ARG);
1518 if (!pwm->ctx)
1519 return FINISH (GPG_ERR_INV_STATE);
1521 command_start (pwm);
1522 rc = disable_pinentry (pwm, &no_pinentry);
1523 if (!rc && !no_pinentry)
1524 rc = send_pinentry_options (pwm);
1526 if (!rc)
1527 rc = pwmd_command (pwm, NULL, NULL, cb, data,
1528 save ? "SAVE %s" : "PASSWD %s", args ? args : "");
1530 pwmd_free (pwm->passphrase_hint);
1531 pwmd_free (pwm->passphrase_info);
1532 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1533 return FINISH (rc);
1536 gpg_error_t
1537 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1539 return do_pwmd_save_passwd (pwm, args, cb, data, 0);
1542 gpg_error_t
1543 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1545 return do_pwmd_save_passwd (pwm, args, cb, data, 1);
1548 static gpg_error_t
1549 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1551 int n, *intp;
1552 size_t *sizetp;
1553 char *arg1, **charpp;
1554 gpg_error_t rc = 0;
1556 if (!pwm)
1557 return GPG_ERR_INV_ARG;
1559 command_start (pwm);
1560 switch (opt)
1562 case PWMD_OPTION_SERVER_VERSION:
1563 if (!get)
1564 return GPG_ERR_NOT_SUPPORTED;
1566 if (!pwm)
1567 rc = GPG_ERR_INV_ARG;
1568 else if (!pwm->ctx)
1569 rc = GPG_ERR_INV_STATE;
1570 else
1572 unsigned *u = va_arg (ap, unsigned *);
1573 *u = pwm->version;
1576 break;
1577 case PWMD_OPTION_SIGPIPE:
1578 if (get)
1580 intp = va_arg (ap, int *);
1581 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1582 break;
1585 n = va_arg (ap, int);
1586 if (n < 0 || n > 1)
1587 rc = GPG_ERR_INV_VALUE;
1589 if (n)
1590 pwm->opts |= OPT_SIGPIPE;
1591 else
1592 pwm->opts &= ~OPT_SIGPIPE;
1594 break;
1595 case PWMD_OPTION_LOCK_ON_OPEN:
1596 if (get)
1598 intp = va_arg (ap, int *);
1599 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1600 break;
1603 n = va_arg (ap, int);
1605 if (n < 0 || n > 1)
1606 rc = GPG_ERR_INV_VALUE;
1608 if (n)
1609 pwm->opts |= OPT_LOCK_ON_OPEN;
1610 else
1611 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1613 break;
1614 case PWMD_OPTION_INQUIRE_TOTAL:
1615 if (get)
1617 sizetp = va_arg (ap, size_t *);
1618 *sizetp = pwm->inquire_total;
1619 break;
1622 pwm->inquire_total = va_arg (ap, size_t);
1623 break;
1624 case PWMD_OPTION_STATUS_CB:
1625 if (get)
1627 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1629 *cb = pwm->status_func;
1630 break;
1633 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1634 break;
1635 case PWMD_OPTION_STATUS_DATA:
1636 if (get)
1638 void **data = va_arg (ap, void **);
1640 *data = pwm->status_data;
1641 break;
1644 pwm->status_data = va_arg (ap, void *);
1645 break;
1646 case PWMD_OPTION_NO_PINENTRY:
1647 if (get)
1649 intp = va_arg (ap, int *);
1650 *intp = pwm->disable_pinentry;
1651 break;
1654 n = va_arg (ap, int);
1656 if (n < 0 || n > 1)
1657 rc = GPG_ERR_INV_VALUE;
1658 else
1659 pwm->disable_pinentry = n;
1660 break;
1661 case PWMD_OPTION_LOCAL_PINENTRY:
1662 if (get)
1664 intp = va_arg (ap, int *);
1665 *intp = pwm->local_pinentry;
1666 break;
1669 n = va_arg (ap, int);
1671 if (n < 0 || n > 1)
1672 rc = GPG_ERR_INV_VALUE;
1673 else
1674 pwm->local_pinentry = n;
1676 break;
1677 case PWMD_OPTION_PINENTRY_TIMEOUT:
1678 if (get)
1680 intp = va_arg (ap, int *);
1681 *intp = pwm->pinentry_timeout;
1682 break;
1685 n = va_arg (ap, int);
1687 if (n < 0)
1688 rc = GPG_ERR_INV_VALUE;
1689 else
1690 pwm->pinentry_timeout = n;
1691 break;
1692 case PWMD_OPTION_PINENTRY_TRIES:
1693 if (get)
1695 intp = va_arg (ap, int *);
1696 *intp = pwm->pinentry_tries;
1697 break;
1700 n = va_arg (ap, int);
1701 pwm->pinentry_tries = n;
1702 break;
1703 case PWMD_OPTION_PINENTRY_PATH:
1704 if (get)
1706 charpp = va_arg (ap, char **);
1707 *charpp = pwm->pinentry_path;
1708 break;
1711 arg1 = va_arg (ap, char *);
1712 pwmd_free (pwm->pinentry_path);
1713 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1714 break;
1715 case PWMD_OPTION_PINENTRY_TTY:
1716 if (get)
1718 charpp = va_arg (ap, char **);
1719 *charpp = pwm->pinentry_tty;
1720 break;
1723 arg1 = va_arg (ap, char *);
1724 pwmd_free (pwm->pinentry_tty);
1725 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1726 break;
1727 case PWMD_OPTION_PINENTRY_DISPLAY:
1728 if (get)
1730 charpp = va_arg (ap, char **);
1731 *charpp = pwm->pinentry_display;
1732 break;
1735 arg1 = va_arg (ap, char *);
1736 pwmd_free (pwm->pinentry_display);
1737 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1738 break;
1739 case PWMD_OPTION_PINENTRY_TERM:
1740 if (get)
1742 charpp = va_arg (ap, char **);
1743 *charpp = pwm->pinentry_term;
1744 break;
1747 arg1 = va_arg (ap, char *);
1748 pwmd_free (pwm->pinentry_term);
1749 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1750 break;
1751 case PWMD_OPTION_PINENTRY_ERROR:
1752 if (get)
1754 charpp = va_arg (ap, char **);
1755 *charpp = pwm->pinentry_error;
1756 break;
1759 arg1 = va_arg (ap, char *);
1760 pwmd_free (pwm->pinentry_error);
1761 if (pwm->disable_pinentry)
1762 pwm->pinentry_error = arg1 ? pwmd_strdup (arg1) : NULL;
1763 else
1764 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1765 break;
1766 case PWMD_OPTION_PINENTRY_PROMPT:
1767 if (get)
1769 charpp = va_arg (ap, char **);
1770 *charpp = pwm->pinentry_prompt;
1771 break;
1774 arg1 = va_arg (ap, char *);
1775 pwmd_free (pwm->pinentry_prompt);
1776 if (pwm->disable_pinentry)
1777 pwm->pinentry_prompt = arg1 ? pwmd_strdup (arg1) : NULL;
1778 else
1779 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1780 break;
1781 case PWMD_OPTION_PINENTRY_DESC:
1782 if (get)
1784 charpp = va_arg (ap, char **);
1785 *charpp = pwm->pinentry_desc;
1786 break;
1789 arg1 = va_arg (ap, char *);
1790 pwmd_free (pwm->pinentry_desc);
1791 if (pwm->disable_pinentry)
1792 pwm->pinentry_desc = arg1 ? pwmd_strdup (arg1) : NULL;
1793 else
1794 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1795 break;
1796 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1797 if (get)
1799 charpp = va_arg (ap, char **);
1800 *charpp = pwm->pinentry_lcctype;
1801 break;
1804 arg1 = va_arg (ap, char *);
1805 pwmd_free (pwm->pinentry_lcctype);
1806 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1807 break;
1808 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1809 if (get)
1811 charpp = va_arg (ap, char **);
1812 *charpp = pwm->pinentry_lcmessages;
1813 break;
1816 arg1 = va_arg (ap, char *);
1817 pwmd_free (pwm->pinentry_lcmessages);
1818 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1819 break;
1820 case PWMD_OPTION_KNOWNHOST_CB:
1821 if (get)
1823 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
1825 *cb = pwm->kh_cb;
1826 break;
1829 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1830 break;
1831 case PWMD_OPTION_KNOWNHOST_DATA:
1832 if (get)
1834 void **data = va_arg (ap, void **);
1836 *data = pwm->kh_data;
1837 break;
1840 pwm->kh_data = va_arg (ap, void *);
1841 break;
1842 case PWMD_OPTION_SSH_AGENT:
1843 if (get)
1845 intp = va_arg (ap, int *);
1846 *intp = pwm->use_agent;
1847 break;
1850 pwm->use_agent = va_arg (ap, int);
1852 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1854 pwm->use_agent = 0;
1855 rc = GPG_ERR_INV_VALUE;
1857 break;
1858 case PWMD_OPTION_SSH_PASSPHRASE:
1859 if (get)
1860 return GPG_ERR_NOT_SUPPORTED;
1861 pwmd_free (pwm->ssh_passphrase);
1862 pwm->ssh_passphrase = NULL;
1863 arg1 = va_arg (ap, char *);
1864 if (arg1)
1866 pwm->ssh_passphrase = pwmd_strdup (arg1);
1867 if (!pwm->ssh_passphrase)
1868 return GPG_ERR_ENOMEM;
1870 break;
1871 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE:
1872 if (get)
1874 intp = va_arg (ap, int *);
1875 *intp = pwm->needs_passphrase;
1876 break;
1879 pwm->needs_passphrase = va_arg (ap, int);
1881 if (pwm->needs_passphrase < 0 || pwm->needs_passphrase > 1)
1883 pwm->needs_passphrase = 0;
1884 rc = GPG_ERR_INV_VALUE;
1886 break;
1887 case PWMD_OPTION_TLS_VERIFY:
1888 if (get)
1890 intp = va_arg (ap, int *);
1891 *intp = pwm->tls_verify;
1892 break;
1895 pwm->tls_verify = va_arg (ap, int);
1897 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1899 pwm->tls_verify = 0;
1900 rc = GPG_ERR_INV_VALUE;
1902 break;
1903 case PWMD_OPTION_SOCKET_TIMEOUT:
1904 if (get)
1906 intp = va_arg (ap, int *);
1907 *intp = pwm->socket_timeout;
1908 break;
1911 pwm->socket_timeout = va_arg (ap, int);
1912 if (pwm->socket_timeout < 0)
1914 pwm->socket_timeout = 0;
1915 rc = GPG_ERR_INV_VALUE;
1918 #ifdef WITH_SSH
1919 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1921 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1922 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1923 pwm->socket_timeout * 1000);
1925 #endif
1926 #ifdef WITH_GNUTLS
1927 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1928 pwm->tcp->tls->timeout = pwm->socket_timeout;
1929 #endif
1930 break;
1931 case PWMD_OPTION_OVERRIDE_INQUIRE:
1932 if (get)
1934 intp = va_arg (ap, int *);
1935 *intp = pwm->override_inquire;
1936 break;
1939 pwm->override_inquire = va_arg (ap, int);
1941 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1943 pwm->override_inquire = 0;
1944 rc = GPG_ERR_INV_VALUE;
1946 break;
1947 default:
1948 rc = GPG_ERR_UNKNOWN_OPTION;
1949 break;
1952 return FINISH (rc);
1955 gpg_error_t
1956 pwmd_setopt (pwm_t * pwm, int opt, ...)
1958 va_list ap;
1959 gpg_error_t rc = 0;
1961 va_start (ap, opt);
1962 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
1963 va_end (ap);
1964 return FINISH (rc);
1967 gpg_error_t
1968 pwmd_getopt (pwm_t *pwm, int opt, ...)
1970 va_list ap;
1971 gpg_error_t rc = 0;
1973 va_start (ap, opt);
1974 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
1975 va_end (ap);
1976 return FINISH (rc);
1979 gpg_error_t
1980 pwmd_new (const char *name, pwm_t ** pwm)
1982 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1983 gpg_error_t rc;
1985 if (!h)
1986 return FINISH (GPG_ERR_ENOMEM);
1988 if (name)
1990 h->name = pwmd_strdup (name);
1991 if (!h->name)
1993 pwmd_free (h);
1994 return FINISH (GPG_ERR_ENOMEM);
1998 reset_handle (h);
1999 h->pinentry_timeout = -1;
2000 h->current_pinentry_timeout = -1;
2001 h->pinentry_tries = 3;
2002 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2003 h->prot = PWMD_IP_ANY;
2004 #endif
2006 if (isatty (STDOUT_FILENO))
2008 char buf[256];
2009 int err = ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
2011 if (!err)
2013 h->pinentry_tty = pwmd_strdup (buf);
2014 if (!h->pinentry_tty)
2016 rc = GPG_ERR_ENOMEM;
2017 goto fail;
2022 if (getenv ("TERM") && h->pinentry_tty)
2024 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
2025 if (!h->pinentry_term)
2027 rc = GPG_ERR_ENOMEM;
2028 goto fail;
2032 if (getenv ("DISPLAY"))
2034 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
2035 if (!h->pinentry_display)
2037 rc = GPG_ERR_ENOMEM;
2038 goto fail;
2042 update_pinentry_settings (h);
2043 *pwm = h;
2044 return 0;
2046 fail:
2047 pwmd_close (h);
2048 return FINISH (rc);
2051 void
2052 pwmd_free (void *ptr)
2054 _xfree (ptr);
2057 void *
2058 pwmd_malloc (size_t size)
2060 return _xmalloc (size);
2063 void *
2064 pwmd_calloc (size_t nmemb, size_t size)
2066 return _xcalloc (nmemb, size);
2069 void *
2070 pwmd_realloc (void *ptr, size_t size)
2072 return _xrealloc (ptr, size);
2075 char *
2076 pwmd_strdup (const char *str)
2078 char *t;
2079 size_t len;
2080 register size_t c;
2082 len = strlen (str);
2083 t = _xmalloc ((len + 1) * sizeof (char));
2084 if (!t)
2085 return NULL;
2087 for (c = 0; c < len; c++)
2088 t[c] = str[c];
2090 t[c] = 0;
2091 return t;
2094 char *
2095 pwmd_strdup_printf (const char *fmt, ...)
2097 va_list ap, ap2;
2098 int len;
2099 char *buf;
2101 if (!fmt)
2102 return NULL;
2104 va_start (ap, fmt);
2105 va_copy (ap2, ap);
2106 len = vsnprintf (NULL, 0, fmt, ap);
2107 va_end (ap);
2108 buf = pwmd_malloc (++len);
2109 if (buf)
2110 vsnprintf (buf, len, fmt, ap2);
2112 va_end (ap2);
2113 return buf;
2116 gpg_error_t
2117 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
2118 size_t * len, pwmd_pinentry_t which)
2120 #ifndef WITH_PINENTRY
2121 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
2122 #else
2123 gpg_error_t rc;
2125 command_start (pwm);
2126 if (which == PWMD_PINENTRY_CONFIRM && pwm->disable_pinentry)
2128 rc = get_password (pwm, NULL, NULL, which, 1);
2129 return FINISH (rc);
2132 rc = _pwmd_getpin (pwm, filename, result, len, which);
2133 return FINISH (rc);
2134 #endif
2137 const char *
2138 pwmd_version ()
2140 return LIBPWMD_VERSION_STR;
2143 unsigned int
2144 pwmd_features ()
2146 unsigned int n = 0;
2148 #ifdef WITH_PINENTRY
2149 n |= PWMD_FEATURE_PINENTRY;
2150 #endif
2151 #ifdef WITH_SSH
2152 n |= PWMD_FEATURE_SSH;
2153 #endif
2154 #ifdef WITH_QUALITY
2155 n |= PWMD_FEATURE_QUALITY;
2156 #endif
2157 #ifdef WITH_GNUTLS
2158 n |= PWMD_FEATURE_GNUTLS;
2159 #endif
2160 return n;
2163 gpg_error_t
2164 pwmd_fd (pwm_t * pwm, int *fd)
2166 if (!pwm || !fd)
2167 return FINISH (GPG_ERR_INV_ARG);
2169 if (pwm->fd == -1)
2170 return FINISH (GPG_ERR_INV_STATE);
2172 *fd = pwm->fd;
2173 return 0;
2176 void
2177 pwmd_set_pointer (pwm_t *pwm, void *data)
2179 pwm->user_data = data;
2182 void *
2183 pwmd_get_pointer (pwm_t *pwm)
2185 return pwm->user_data;
2189 pwmd_gnutls_error (pwm_t *pwm, const char **str)
2191 #ifndef WITH_GNUTLS
2192 return 0;
2193 #else
2194 if (str && pwm && pwm->tls_error)
2195 *str = gnutls_strerror (pwm->tls_error);
2197 return pwm ? pwm->tls_error : 0;
2198 #endif
2201 gpg_error_t
2202 pwmd_cancel (pwm_t *pwm)
2204 if (!pwm)
2205 return FINISH (GPG_ERR_INV_ARG);
2207 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2208 if (pwm->fd == -1 && !pwm->tcp)
2209 #else
2210 if (pwm->fd == -1)
2211 #endif
2212 return FINISH (GPG_ERR_INV_STATE);
2214 /* Can only cancel the connection for the time being. */
2215 if (pwm->connected)
2216 return FINISH (GPG_ERR_INV_STATE);
2218 pwm->cancel = 1;
2219 return 0;
2222 gpg_error_t
2223 pwmd_test_quality (const char *str, double *result)
2225 #ifndef WITH_QUALITY
2226 return GPG_ERR_NOT_IMPLEMENTED;
2227 #else
2228 if (!result)
2229 return GPG_ERR_INV_ARG;
2231 *result = ZxcvbnMatch (str, NULL, NULL);
2232 return 0;
2233 #endif