Port to Windows.
[libpwmd.git] / src / libpwmd.c
blob809c60abe01a7bfacb931200a18a5a1157d47fef
1 /*
2 Copyright (C) 2006-2016, 2017 Ben Kibbey <bjk@luxsci.net>
4 This file is part of libpwmd.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library 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 GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
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 <errno.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <time.h>
37 #include <limits.h>
39 #ifndef __MINGW32__
40 #include <err.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #include <sys/wait.h>
44 #include <pwd.h>
45 #include <sys/select.h>
46 #include <termios.h>
47 #endif
49 #include <libpwmd.h>
51 #ifdef HAVE_STRINGS_H
52 #include <strings.h>
53 #endif
55 #ifndef LINE_MAX
56 #define LINE_MAX 2048
57 #endif
59 #include "mem.h"
60 #include "misc.h"
61 #include "types.h"
63 #ifdef WITH_PINENTRY
64 #include "pinentry.h"
65 #endif
67 #ifdef WITH_QUALITY
68 #include "zxcvbn.h"
69 #endif
71 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
72 #include <sys/types.h>
73 #ifndef __MINGW32__
74 #include <sys/socket.h>
75 #include <netdb.h>
76 #include <netinet/in.h>
77 #endif
78 #endif
80 enum
82 PWMD_WHICH_SAVE,
83 PWMD_WHICH_PASSWD,
84 PWMD_WHICH_GENKEY
87 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
88 ? gpg_error(rc) : rc
90 typedef struct
92 size_t len;
93 void *buf;
94 } membuf_t;
96 static gpg_error_t status_cb (void *data, const char *line);
98 ssize_t
99 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
101 pwm_t *pwm = assuan_get_pointer (ctx);
103 if (pwm->read_cb)
104 return pwm->read_cb (pwm->read_cb_data, HANDLE2SOCKET (fd), data, len);
106 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
107 #ifdef WITH_SSH
108 if (pwm && pwm->tcp && pwm->tcp->ssh)
110 ssize_t ret = read_hook_ssh (pwm->tcp->ssh, fd, data, len);
112 if (ret == -1)
114 int e = errno;
116 __assuan_close (ctx, pwm->fd);
117 pwm->fd = ASSUAN_INVALID_FD;
118 errno = e;
121 return ret;
123 #endif
124 #ifdef WITH_GNUTLS
125 if (pwm && pwm->tcp && pwm->tcp->tls)
126 return tls_read_hook (pwm, fd, data, len);
127 #endif
128 #endif
130 return read (HANDLE2SOCKET (fd), data, len);
133 ssize_t
134 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
135 size_t len)
137 pwm_t *pwm = assuan_get_pointer (ctx);
138 ssize_t wrote;
140 if (pwm->write_cb)
141 return pwm->write_cb (pwm->write_cb_data, HANDLE2SOCKET (fd), data, len);
143 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
144 #ifdef WITH_SSH
145 if (pwm && pwm->tcp && pwm->tcp->ssh)
147 ssize_t ret = write_hook_ssh (pwm->tcp->ssh, fd, data, len);
149 if (ret == -1)
151 int e = errno;
153 __assuan_close (ctx, pwm->fd);
154 pwm->fd = ASSUAN_INVALID_FD;
155 errno = e;
158 return ret;
160 #endif
161 #ifdef WITH_GNUTLS
162 if (pwm && pwm->tcp && pwm->tcp->tls)
163 return tls_write_hook (pwm, fd, data, len);
164 #endif
165 #endif
167 /* libassuan cannot handle EAGAIN when doing writes. */
170 wrote = write (HANDLE2SOCKET (fd), data, len);
171 if (wrote == -1 && errno == EAGAIN)
172 __assuan_usleep (pwm->ctx, 50000);
174 while (wrote == -1 && errno == EAGAIN);
176 return wrote;
179 #ifndef __MINGW32__
180 pid_t
181 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
182 int options)
184 (void)ctx;
185 (void)action;
186 return waitpid (pid, status, options);
188 #endif
190 gpg_error_t
191 pwmd_init ()
193 static int initialized;
195 #ifdef WITH_GNUTLS
196 // May be called more than once.
197 gnutls_global_init ();
198 #endif
200 if (initialized)
201 return 0;
203 #ifdef ENABLE_NLS
204 bindtextdomain ("libpwmd", LOCALEDIR);
205 #endif
206 #ifdef WITH_SSH
207 libssh2_init (0);
208 #endif
209 gpgrt_init ();
210 //gpgrt_set_alloc_func (_xrealloc_gpgrt);
212 #ifdef WITH_QUALITY
213 ZxcvbnInit (NULL);
214 #endif
216 initialized = 1;
217 return 0;
220 void
221 pwmd_deinit ()
223 #ifdef WITH_GNUTLS
224 gnutls_global_deinit ();
225 #endif
226 #ifdef WITH_QUALITY
227 ZxcvbnUnInit();
228 #endif
231 gpg_error_t
232 _connect_finalize (pwm_t * pwm)
234 gpg_error_t rc = 0;
235 char *result = NULL;
236 assuan_fd_t active[2];
237 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
239 if (n <= 0)
240 return GPG_ERR_EBADFD;
242 pwm->fd = active[0];
243 #ifdef WITH_PINENTRY
244 pwm->pinentry_pid = -1;
245 #endif
247 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "GETINFO VERSION");
248 if (!rc)
250 pwm->version = strtoul (result, NULL, 16);
251 pwmd_free (result);
254 if (!rc && pwm->name)
255 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
256 pwm->name);
258 return rc;
261 static gpg_error_t
262 connect_uds (pwm_t * pwm, const char *path)
264 #ifdef __MINGW32__
265 return GPG_ERR_UNSUPPORTED_PROTOCOL;
266 #else
267 if (!pwm)
268 return GPG_ERR_INV_ARG;
270 char *socketpath = NULL;
271 struct passwd pw;
272 char *pwbuf;
273 gpg_error_t rc;
275 pwbuf = _getpwuid (&pw);
276 if (!pwbuf)
277 return gpg_error_from_syserror ();
279 if (!path || !*path)
280 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
281 else
282 socketpath = _expand_homedir ((char *) path, &pw);
284 pwmd_free (pwbuf);
285 if (!socketpath)
286 return GPG_ERR_ENOMEM;
288 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
289 pwmd_free (socketpath);
290 return rc ? rc : _connect_finalize (pwm);
291 #endif
294 static gpg_error_t
295 init_handle (pwm_t * pwm)
297 gpg_error_t rc;
298 static struct assuan_malloc_hooks mhooks = {
299 pwmd_malloc, pwmd_realloc, pwmd_free
301 static struct assuan_system_hooks shooks = {
302 ASSUAN_SYSTEM_HOOKS_VERSION,
303 __assuan_usleep,
304 __assuan_pipe,
305 __assuan_close,
306 hook_read,
307 hook_write,
308 //FIXME
309 NULL, //recvmsg
310 NULL, //sendmsg both are used for FD passing
311 __assuan_spawn,
312 #ifdef __MINGW32__
313 __assuan_waitpid,
314 #else
315 hook_waitpid,
316 #endif
317 __assuan_socketpair,
318 __assuan_socket,
319 __assuan_connect
322 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
323 NULL);
324 if (rc)
325 return rc;
327 assuan_set_pointer (pwm->ctx, pwm);
328 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
329 return 0;
332 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
333 void
334 free_tcp (pwm_t *pwm)
336 struct tcp_s *tcp = pwm->tcp;
338 if (!tcp)
339 return;
341 #ifdef WITH_SSH
342 _free_ssh_conn (tcp->ssh);
343 #endif
344 #ifdef WITH_GNUTLS
345 tls_free (pwm);
346 #endif
348 pwmd_free (tcp->host);
349 if (tcp->addrs)
351 freeaddrinfo (tcp->addrs);
352 tcp->addrs = NULL;
355 pthread_cond_destroy (&tcp->dns_cond);
356 pthread_mutex_destroy (&tcp->dns_mutex);
357 pwmd_free (tcp);
358 pwm->tcp = NULL;
360 #endif
362 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
363 static void *
364 resolve_host_thread (void *arg)
366 pwm_t *pwm = arg;
367 struct addrinfo hints = { 0 };
368 char portstr[6];
370 switch (pwm->prot)
372 case PWMD_IP_ANY:
373 hints.ai_family = AF_UNSPEC;
374 break;
375 case PWMD_IPV4:
376 hints.ai_family = AF_INET;
377 break;
378 case PWMD_IPV6:
379 hints.ai_family = AF_INET6;
380 break;
383 hints.ai_socktype = SOCK_STREAM;
384 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
385 int *n = pwmd_malloc (sizeof (int));
386 pthread_cleanup_push (pwmd_free, n);
387 *n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
388 pthread_cleanup_pop (0);
389 pthread_cond_broadcast (&pwm->tcp->dns_cond);
390 pthread_exit (n);
391 return NULL;
394 gpg_error_t
395 tcp_connect_common (pwm_t * pwm)
397 #define TS_TIMEOUT 50000000L
398 int n;
399 gpg_error_t rc = 0;
400 pthread_t tid;
401 time_t now;
403 time (&now);
404 n = pthread_create (&tid, NULL, resolve_host_thread, pwm);
405 if (n)
406 return gpg_error_from_errno (n);
408 pthread_mutex_lock (&pwm->tcp->dns_mutex);
410 for (;;)
412 struct timespec ts;
413 int *result = NULL;
415 clock_gettime (CLOCK_REALTIME, &ts);
416 if (ts.tv_nsec + TS_TIMEOUT >= 1000000000LL) {
417 ts.tv_sec++;
418 ts.tv_nsec = 0;
420 else
421 ts.tv_nsec += TS_TIMEOUT;
423 if (pwm->cancel)
425 #ifdef HAVE_PTHREAD_CANCEL
426 pthread_cancel (tid);
427 pthread_join (tid, NULL);
428 #else
429 pthread_join (tid, (void **)&result);
430 pwmd_free (result);
431 #endif
432 return GPG_ERR_CANCELED;
435 n = pthread_cond_timedwait (&pwm->tcp->dns_cond, &pwm->tcp->dns_mutex,
436 &ts);
437 if (n == ETIMEDOUT)
439 if (pwm->socket_timeout && ts.tv_sec - now >= pwm->socket_timeout)
441 #ifdef HAVE_PTHREAD_CANCEL
442 pthread_cancel (tid);
443 pthread_join (tid, NULL);
444 #else
445 pthread_join (tid, (void **)&result);
446 pwmd_free (result);
447 #endif
448 return GPG_ERR_ETIMEDOUT;
451 continue;
453 else if (n)
455 #ifdef HAVE_PTHREAD_CANCEL
456 pthread_cancel (tid);
457 pthread_join (tid, NULL);
458 #else
459 pthread_join (tid, (void **)&result);
460 pwmd_free (result);
461 #endif
462 return gpg_error_from_errno (n);
465 pthread_join (tid, (void **)&result);
466 n = *result;
467 pwmd_free (result);
468 break;
471 if (n)
472 return GPG_ERR_UNKNOWN_HOST; //FIXME
474 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
475 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
477 #ifdef __MINGW32__
478 pwm->fh = _open_osfhandle (socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0), 0);
479 pwm->fd = SOCKET2HANDLE (_get_osfhandle (pwm->fh));
480 #else
481 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
482 #endif
483 if (pwm->fd == ASSUAN_INVALID_FD)
485 rc = gpg_error_from_syserror ();
486 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
487 break;
488 continue;
491 rc = set_non_blocking (pwm->fd, 1);
492 if (rc)
494 __assuan_close (pwm->ctx, pwm->fd);
495 pwm->fd = ASSUAN_INVALID_FD;
496 break;
499 if (connect (HANDLE2SOCKET (pwm->fd), pwm->tcp->addr->ai_addr,
500 pwm->tcp->addr->ai_family == AF_INET6
501 ? sizeof (struct sockaddr_in6)
502 : sizeof (struct sockaddr)) == -1)
504 struct timeval tv;
505 fd_set wfds;
506 unsigned elapsed = 0;
508 rc = gpg_error_from_syserror ();
509 #ifdef __MINGW32__
510 int w = WSAGetLastError ();
511 switch (w)
513 case WSAEINPROGRESS:
514 case WSAEWOULDBLOCK:
515 rc = GPG_ERR_EINPROGRESS;
516 break;
517 default:
518 break;
520 #endif
522 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
524 __assuan_close (pwm->ctx, pwm->fd);
525 pwm->fd = ASSUAN_INVALID_FD;
526 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
527 return rc;
528 continue;
531 again:
532 tv.tv_sec = 1;
533 tv.tv_usec = 0;
534 FD_ZERO (&wfds);
535 FD_SET (HANDLE2SOCKET (pwm->fd), &wfds);
536 n = select (HANDLE2SOCKET (pwm->fd)+1, NULL, &wfds, NULL, &tv);
537 rc = 0;
538 if (!n || pwm->cancel)
540 if (pwm->cancel)
541 rc = gpg_error (GPG_ERR_CANCELED);
542 else if (++elapsed >= pwm->socket_timeout)
543 rc = gpg_error (GPG_ERR_ETIMEDOUT);
544 else
545 goto again;
547 else if (n != -1)
549 socklen_t len = sizeof (int);
550 #ifdef __MINGW32__
551 char ret;
553 len = sizeof (char);
554 getsockopt (HANDLE2SOCKET (pwm->fd), SOL_SOCKET, SO_ERROR, &ret, &len);
555 if (ret)
556 rc = gpg_error_from_errno (ret);
557 #else
558 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
559 if (n)
560 rc = gpg_error_from_errno (n);
561 #endif
563 else if (n == -1)
564 rc = gpg_error_from_syserror ();
566 if (rc)
568 __assuan_close (pwm->ctx, pwm->fd);
569 pwm->fd = ASSUAN_INVALID_FD;
570 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
571 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
572 || pwm->cancel)
573 return rc;
575 else
576 break;
578 else
579 break;
582 if (!rc)
584 rc = set_non_blocking (pwm->fd, 0);
585 if (rc)
587 __assuan_close (pwm->ctx, pwm->fd);
588 pwm->fd = ASSUAN_INVALID_FD;
592 return rc;
594 #endif
596 static void
597 command_start (pwm_t *pwm)
599 pwm->cancel = 0;
602 gpg_error_t
603 pwmd_connect_fd (pwm_t * pwm, int fd)
605 gpg_error_t rc = 0;
607 if (!pwm)
608 return FINISH (GPG_ERR_INV_ARG);
609 else if (!pwm->ctx)
611 rc = init_handle (pwm);
612 if (rc)
613 return FINISH (rc);
615 else if (pwm->fd != ASSUAN_INVALID_FD)
616 return FINISH (GPG_ERR_INV_STATE);
618 command_start (pwm);
620 #ifndef __MINGW32__
621 if (!(pwm->opts & OPT_SIGPIPE))
622 signal (SIGPIPE, SIG_IGN);
623 #endif
625 rc = assuan_socket_connect_fd (pwm->ctx, fd, 0);
626 if (!rc)
628 pwm->fd = SOCKET2HANDLE (fd);
629 pwm->connected = pwm->user_fd = 1;
630 rc = _connect_finalize (pwm);
633 if (rc)
634 pwmd_disconnect (pwm);
636 return FINISH (rc);
639 gpg_error_t
640 pwmd_connect (pwm_t * pwm, const char *url, ...)
642 const char *p = url;
643 gpg_error_t rc;
645 if (!pwm)
646 return FINISH (GPG_ERR_INV_ARG);
647 else if (!pwm->ctx)
649 rc = init_handle (pwm);
650 if (rc)
651 return FINISH (GPG_ERR_INV_ARG);
653 else if (pwm->fd != ASSUAN_INVALID_FD)
654 return FINISH (GPG_ERR_INV_STATE);
656 command_start (pwm);
658 #ifndef __MINGW32__
659 if (!(pwm->opts & OPT_SIGPIPE))
660 signal (SIGPIPE, SIG_IGN);
661 #endif
663 #ifdef WITH_GNUTLS
664 pwm->tls_error = 0;
665 #endif
666 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
668 if (p && (*p == '/' || *p == '~'))
669 rc = connect_uds (pwm, p);
670 else if (!p || !strncmp (p, "file://", 7))
672 if (p)
673 p += 7;
674 #ifdef DEFAULT_PWMD_SOCKET
675 else
676 p = DEFAULT_PWMD_SOCKET;
677 #endif
678 rc = connect_uds (pwm, p);
680 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
681 !strncmp (p, "ssh4://", 7))
683 #ifndef WITH_SSH
684 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
685 #else
686 char *host = NULL;
687 int port;
688 char *username = NULL;
690 if (!strncmp (p, "ssh6://", 7))
692 pwm->prot = PWMD_IPV6;
693 p += 7;
695 else if (!strncmp (p, "ssh4://", 7))
697 pwm->prot = PWMD_IPV4;
698 p += 7;
700 else
702 pwm->prot = PWMD_IP_ANY;
703 p += 6;
706 rc = _parse_ssh_url (p, &host, &port, &username);
707 if (!rc)
709 va_list ap;
710 char *identity = NULL;
711 char *knownhosts = NULL;
713 va_start (ap, url);
714 identity = va_arg (ap, char *);
716 if (!identity && !pwm->use_agent)
717 rc = GPG_ERR_INV_ARG;
718 else
719 knownhosts = va_arg (ap, char *);
721 va_end (ap);
723 if (!rc)
724 rc = _do_ssh_connect (pwm, host, port, identity, username,
725 knownhosts);
726 if (!rc)
728 rc = _connect_finalize (pwm);
729 if (rc)
730 free_tcp (pwm);
734 pwmd_free (host);
735 pwmd_free (username);
736 pwm->local_pinentry = 1;
737 pwmd_free (pwm->ssh_passphrase);
738 pwm->ssh_passphrase = NULL;
739 #endif
741 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
742 !strncmp (p, "tls4://", 7))
744 #ifndef WITH_GNUTLS
745 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
746 #else
747 char *host = NULL;
748 int port;
750 if (!strncmp (p, "tls6://", 7))
752 pwm->prot = PWMD_IPV6;
753 p += 7;
755 else if (!strncmp (p, "tls4://", 7))
757 pwm->prot = PWMD_IPV4;
758 p += 7;
760 else
762 pwm->prot = PWMD_IP_ANY;
763 p += 6;
766 rc = tls_parse_url (p, &host, &port);
767 if (!rc)
769 va_list ap;
770 char *clientcert = NULL;
771 char *clientkey = NULL;
772 char *cacert = NULL;
773 char *server_fp = NULL;
775 va_start (ap, url);
776 clientcert = va_arg (ap, char *);
778 if (!clientcert)
779 rc = GPG_ERR_INV_ARG;
780 else
782 clientkey = va_arg (ap, char *);
783 if (!clientkey)
784 rc = GPG_ERR_INV_ARG;
785 else
787 cacert = va_arg (ap, char *);
788 if (!cacert)
789 rc = GPG_ERR_INV_ARG;
790 else
791 server_fp = va_arg (ap, char *);
795 va_end (ap);
797 if (!rc)
798 rc = tls_connect (pwm, host, port, clientcert, clientkey, cacert,
799 pwm->tls_priority, server_fp, pwm->tls_verify);
800 if (!rc)
802 rc = _connect_finalize (pwm);
803 if (rc)
804 free_tcp (pwm);
808 pwmd_free (host);
809 pwm->local_pinentry = 1;
810 #endif
813 if (!rc)
814 pwm->connected = 1;
816 return FINISH (rc);
819 static void
820 disconnect (pwm_t * pwm)
822 if (!pwm)
823 return;
825 if (pwm->ctx)
826 assuan_release (pwm->ctx);
828 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
829 free_tcp (pwm);
830 #endif
831 pwm->ctx = NULL;
832 pwm->fd = ASSUAN_INVALID_FD;
833 pwm->connected = 0;
834 pwm->user_fd = -1;
837 void
838 pwmd_close (pwm_t * pwm)
840 if (!pwm)
841 return;
843 disconnect (pwm);
844 pwmd_free (pwm->pinentry_error);
845 pwmd_free (pwm->pinentry_desc);
846 pwmd_free (pwm->pinentry_prompt);
847 pwmd_free (pwm->pinentry_tty);
848 pwmd_free (pwm->pinentry_display);
849 pwmd_free (pwm->pinentry_term);
850 pwmd_free (pwm->pinentry_lcctype);
851 pwmd_free (pwm->pinentry_lcmessages);
852 pwmd_free (pwm->filename);
853 pwmd_free (pwm->name);
854 pwmd_free (pwm->passphrase_info);
855 pwmd_free (pwm->passphrase_hint);
856 pwmd_free (pwm->ssh_passphrase);
857 pwmd_free (pwm->tls_priority);
859 #ifdef WITH_PINENTRY
860 if (pwm->pctx)
861 _pinentry_disconnect (pwm);
862 #endif
864 pwmd_free (pwm);
867 static gpg_error_t
868 inquire_realloc_cb (void *data, const void *buffer, size_t len)
870 membuf_t *mem = (membuf_t *) data;
871 void *p;
873 if (!buffer)
874 return 0;
876 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
877 return gpg_error (GPG_ERR_ENOMEM);
879 mem->buf = p;
880 memcpy ((char *) mem->buf + mem->len, buffer, len);
881 mem->len += len;
882 return 0;
885 static gpg_error_t
886 get_password (pwm_t * pwm, char **result, size_t * len,
887 pwmd_pinentry_t w, int echo)
889 char buf[ASSUAN_LINELENGTH+1] = { 0 }, *p;
890 #ifndef __MINGW32__
891 struct termios told, tnew;
892 #endif
893 char *key = NULL;
895 if (result)
896 *result = NULL;
898 if (len)
899 *len = 0;
901 if (!isatty (STDIN_FILENO))
903 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
904 return GPG_ERR_ENOTTY;
907 #ifndef __MINGW32__
908 if (!echo)
910 if (tcgetattr (STDIN_FILENO, &told) == -1)
911 return gpg_error_from_syserror ();
913 memcpy (&tnew, &told, sizeof (struct termios));
914 tnew.c_lflag &= ~(ECHO);
915 tnew.c_lflag |= ICANON | ECHONL;
917 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
919 int n = errno;
921 tcsetattr (STDIN_FILENO, TCSANOW, &told);
922 return gpg_error_from_errno (n);
925 #endif
927 if (pwm->passphrase_hint)
928 fprintf(stderr, N_("Key info: %s\n"), pwm->passphrase_hint);
930 switch (w)
932 case PWMD_PINENTRY_OPEN:
933 fprintf (stderr, N_("Passphrase for %s: "), pwm->filename);
934 break;
935 case PWMD_PINENTRY_OPEN_FAILED:
936 fprintf (stderr, N_("Invalid passphrase. Passphrase for %s: "),
937 pwm->filename);
938 break;
939 case PWMD_PINENTRY_SAVE:
940 fprintf (stderr, N_("New passphrase for %s: "), pwm->filename);
941 break;
942 case PWMD_PINENTRY_SAVE_CONFIRM:
943 fprintf (stderr, N_("Repeat passphrase: "));
944 break;
945 case PWMD_PINENTRY_CONFIRM:
946 if (pwm->pinentry_desc)
947 fprintf (stderr, "%s", pwm->pinentry_desc);
949 if (pwm->pinentry_prompt)
950 fprintf (stderr, "%s", pwm->pinentry_prompt);
951 else
952 fprintf(stderr, N_("Confirm [y/N]:"));
953 default:
954 break;
957 p = fgets (buf, sizeof (buf), stdin);
959 #ifndef __MINGW32__
960 if (!echo)
961 tcsetattr (STDIN_FILENO, TCSANOW, &told);
962 #endif
964 if (!p || feof (stdin))
966 clearerr (stdin);
967 return GPG_ERR_CANCELED;
970 /* Strip the newline character. */
971 p[strlen (p) - 1] = 0;
973 if (buf[0])
975 if (w == PWMD_PINENTRY_CONFIRM)
977 if (*p != 'y' && *p != 'Y')
978 return GPG_ERR_CANCELED;
979 return 0;
982 key = pwmd_strdup_printf ("%s", p);
983 wipememory (buf, 0, sizeof (buf));
984 if (!key)
985 return GPG_ERR_ENOMEM;
987 if (result)
988 *result = key;
990 if (len)
991 *len = strlen (key);
993 else
995 if (w == PWMD_PINENTRY_CONFIRM)
996 return GPG_ERR_CANCELED;
998 /* To satisfy inquire_cb(). */
999 if (result)
1000 *result = pwmd_strdup ("");
1002 if (len)
1003 *len = 1;
1006 return 0;
1009 gpg_error_t
1010 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
1012 gpg_error_t rc;
1013 int new_password = 0;
1014 char *password = NULL, *newpass = NULL;
1015 int error = 0;
1017 command_start (pwm);
1019 if (data)
1020 *data = NULL;
1022 if (size)
1023 *size = 0;
1025 if (!strcmp (keyword, "NEW_PASSPHRASE"))
1026 new_password = 1;
1028 if (!new_password && pwm->pinentry_try)
1029 error = 1;
1031 again:
1032 if (pwm->disable_pinentry)
1034 rc = get_password (pwm, &password, size,
1035 new_password ? PWMD_PINENTRY_SAVE :
1036 error ? PWMD_PINENTRY_OPEN_FAILED :
1037 PWMD_PINENTRY_OPEN, 0);
1038 if (!rc && new_password)
1039 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
1042 else
1044 pwmd_pinentry_t which;
1046 if (error)
1047 which = new_password
1048 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
1049 else
1050 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
1052 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
1053 if (!rc && new_password)
1054 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
1055 PWMD_PINENTRY_SAVE_CONFIRM);
1058 if (!rc && new_password)
1060 if ((!password && newpass) || (!newpass && password)
1061 || (newpass && password && strcmp (newpass, password)))
1063 if (pwm->disable_pinentry)
1064 fprintf (stderr, N_("Passphrases do not match.\n"));
1066 pwmd_free (password);
1067 pwmd_free (newpass);
1068 password = newpass = NULL;
1069 error = 1;
1070 goto again;
1074 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
1075 pwmd_free (newpass);
1076 if (!rc && data)
1077 *data = password;
1078 else
1079 pwmd_free (password);
1081 return rc;
1084 static gpg_error_t
1085 inquire_cb (void *data, const char *keyword)
1087 pwm_t *pwm = (pwm_t *) data;
1088 gpg_error_t rc = 0;
1089 int free_result = 0;
1090 char *result = NULL;
1091 int is_password = 0;
1092 int new_password = 0;
1094 if (!strcmp (keyword, "PASSPHRASE") || !strcmp (keyword, "SIGN_PASSPHRASE"))
1095 is_password = 1;
1096 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
1097 new_password = 1;
1099 /* Shouldn't get this far without a callback. */
1100 if (!pwm->override_inquire && !pwm->inquire_func
1101 && !is_password && !new_password)
1102 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
1104 for (;;)
1106 size_t len = 0;
1107 gpg_error_t arc;
1109 result = NULL;
1111 if (!pwm->override_inquire && (is_password || new_password))
1113 free_result = 1;
1114 rc = pwmd_password (data, keyword, &result, &len);
1115 if (!rc)
1116 rc = GPG_ERR_EOF;
1118 else
1119 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
1120 &len);
1122 /* gpg will truncate a passphrase at the first nil byte which may be bad
1123 * for generated key files. */
1124 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
1125 && (is_password || new_password))
1127 if (len && result && *result)
1129 for (size_t n = 0; n < len; n++)
1131 if (result[n] == 0 && n+1 != len)
1132 rc = GPG_ERR_INV_PASSPHRASE;
1137 cancel:
1138 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
1140 #ifndef LIBASSUAN_2_1_0
1141 gpg_error_t trc = rc;
1143 /* Cancel this inquire. */
1144 rc = assuan_send_data (pwm->ctx, NULL, 1);
1145 if (!rc)
1147 char *line;
1148 size_t len;
1150 /* There is a bug (or feature?) in assuan_send_data() that
1151 * when cancelling an inquire the next read from the server is
1152 * not done until the next command making the next command
1153 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
1155 rc = assuan_read_line (pwm->ctx, &line, &len);
1157 /* Restore the original error. This differs from the error
1158 * returned from the pwmd command (GPG_ERR_CANCELED). This
1159 * error is returned to the calling function.
1161 if (!rc)
1162 rc = trc;
1164 #endif
1165 break;
1168 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
1170 if (len <= 0 && !result)
1172 rc = 0;
1173 break;
1175 else if ((len <= 0 && result) || (len && !result))
1177 rc = gpg_error (GPG_ERR_INV_ARG);
1178 break;
1181 if (pwm->inquire_maxlen
1182 && pwm->inquire_sent + len > pwm->inquire_maxlen)
1184 rc = gpg_error (GPG_ERR_TOO_LARGE);
1185 if (!free_result)
1186 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
1187 &result, &len);
1188 goto cancel;
1191 arc = assuan_send_data (pwm->ctx, result, len);
1192 if (gpg_err_code (rc) == GPG_ERR_EOF)
1194 rc = arc;
1195 break;
1198 rc = arc;
1200 else if (rc)
1201 break;
1203 if (!rc)
1205 pwm->inquire_sent += len;
1207 if (pwm->status_func)
1209 char buf[ASSUAN_LINELENGTH];
1211 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
1212 pwm->inquire_total);
1213 rc = pwm->status_func (pwm->status_data, buf);
1214 if (rc)
1215 continue;
1220 if (free_result)
1221 pwmd_free (result);
1223 pwm->inquire_maxlen = pwm->inquire_sent = 0;
1224 return rc;
1227 static gpg_error_t
1228 parse_assuan_line (pwm_t * pwm)
1230 gpg_error_t rc;
1231 char *line;
1232 size_t len;
1234 rc = assuan_read_line (pwm->ctx, &line, &len);
1235 if (!rc)
1237 if (line[0] == 'O' && line[1] == 'K' &&
1238 (line[2] == 0 || line[2] == ' '))
1241 else if (line[0] == '#')
1244 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
1246 rc = status_cb (pwm, line[1] == 0 ? line + 1 : line + 2);
1248 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
1249 (line[3] == 0 || line[3] == ' '))
1251 line += 4;
1252 rc = strtol (line, NULL, 10);
1256 return rc;
1259 static void
1260 reset_handle (pwm_t *pwm)
1262 pwm->fd = ASSUAN_INVALID_FD;
1263 pwm->user_fd = -1;
1264 pwm->cancel = 0;
1265 pwm->pinentry_disabled = 0;
1266 #ifdef WITH_PINENTRY
1267 if (pwm->pctx)
1268 _pinentry_disconnect (pwm);
1269 #endif
1270 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1271 #ifdef WITH_GNUTLS
1272 pwm->tls_error = 0;
1273 #endif
1275 if (pwm->tcp)
1277 pwm->tcp->rc = 0;
1279 #endif
1282 gpg_error_t
1283 pwmd_disconnect (pwm_t * pwm)
1285 if (!pwm)
1286 return FINISH (GPG_ERR_INV_ARG);
1288 command_start (pwm);
1290 if (pwm->fd == ASSUAN_INVALID_FD)
1291 return FINISH (GPG_ERR_INV_STATE);
1293 disconnect (pwm);
1294 reset_handle (pwm);
1295 return 0;
1298 /* Note that this should only be called when not in a command. */
1299 gpg_error_t
1300 pwmd_process (pwm_t * pwm)
1302 gpg_error_t rc = 0;
1303 fd_set fds;
1304 struct timeval tv = { 0, 0 };
1305 int n;
1307 if (!pwm || pwm->fd == ASSUAN_INVALID_FD)
1308 return FINISH (GPG_ERR_INV_ARG);
1309 else if (!pwm->ctx)
1310 return FINISH (GPG_ERR_INV_STATE);
1312 FD_ZERO (&fds);
1313 FD_SET (HANDLE2SOCKET (pwm->fd), &fds);
1314 n = select (HANDLE2SOCKET (pwm->fd) + 1, &fds, NULL, NULL, &tv);
1316 if (n == -1)
1317 return FINISH (gpg_error_from_syserror ());
1319 if (n > 0)
1321 if (FD_ISSET (HANDLE2SOCKET (pwm->fd), &fds))
1322 rc = parse_assuan_line (pwm);
1325 while (!rc && assuan_pending_line (pwm->ctx))
1326 rc = parse_assuan_line (pwm);
1328 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1329 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1331 __assuan_close (pwm->ctx, pwm->fd);
1332 pwm->fd = ASSUAN_INVALID_FD;
1334 #endif
1336 return FINISH (rc);
1339 static gpg_error_t
1340 status_cb (void *data, const char *line)
1342 pwm_t *pwm = data;
1344 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1345 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1346 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1348 pwmd_free (pwm->passphrase_hint);
1349 pwm->passphrase_hint = pwmd_strdup (line+16);
1351 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1353 pwmd_free (pwm->passphrase_info);
1354 pwm->passphrase_info = pwmd_strdup (line+16);
1356 #ifdef WITH_GNUTLS
1357 else if (!strcmp (line, "REHANDSHAKE"))
1359 char buf[32];
1360 ssize_t ret;
1362 ret = tls_read_hook (pwm, pwm->fd, buf, sizeof (buf));
1363 if (ret < 0)
1365 pwm->tls_error = ret;
1366 return GPG_ERR_GENERAL;
1369 #endif
1371 if (pwm->status_func)
1372 return pwm->status_func (pwm->status_data, line);
1374 return 0;
1377 gpg_error_t
1378 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1379 char **result, size_t * len, const char *cmd)
1381 membuf_t data;
1382 gpg_error_t rc;
1384 if (!cmd || !*cmd)
1385 return FINISH (GPG_ERR_INV_ARG);
1387 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1388 return FINISH (GPG_ERR_LINE_TOO_LONG);
1390 data.len = 0;
1391 data.buf = NULL;
1392 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1393 #if WITH_QUALITY && WITH_PINENTRY
1394 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1395 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1396 #else
1397 inquire_cb, pwm,
1398 #endif
1399 status_cb, pwm);
1401 if (rc)
1403 if (data.buf)
1405 pwmd_free (data.buf);
1406 data.buf = NULL;
1409 else
1411 if (data.buf)
1413 inquire_realloc_cb (&data, "", 1);
1415 if (result)
1416 *result = (char *) data.buf;
1417 else
1418 pwmd_free (data.buf);
1420 if (len)
1421 *len = data.len;
1425 pwm->inquire_maxlen = 0;
1426 return rc;
1429 gpg_error_t
1430 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1431 pwmd_inquire_cb_t func, void *user, const char *cmd,
1432 va_list ap)
1434 char *buf;
1435 size_t len;
1436 va_list ap2;
1438 if (!pwm)
1439 return GPG_ERR_INV_ARG;
1441 command_start (pwm);
1443 if (result)
1444 *result = NULL;
1446 if (rlen)
1447 *rlen = 0;
1449 if (!pwm || !cmd)
1450 return FINISH (GPG_ERR_INV_ARG);
1451 if (!pwm->ctx)
1452 return FINISH (GPG_ERR_INV_STATE);
1455 * C99 allows the dst pointer to be null which will calculate the length
1456 * of the would-be result and return it.
1458 va_copy (ap2, ap);
1459 len = vsnprintf (NULL, 0, cmd, ap);
1460 buf = (char *) pwmd_malloc (len+1);
1461 if (!buf)
1463 va_end (ap2);
1464 return FINISH (GPG_ERR_ENOMEM);
1467 if (vsnprintf (buf, len+1, cmd, ap2) != len)
1469 pwmd_free (buf);
1470 va_end (ap2);
1471 return FINISH (GPG_ERR_ENOMEM);
1474 if (buf[strlen (buf) - 1] == '\n')
1475 buf[strlen (buf) - 1] = 0;
1476 if (buf[strlen (buf) - 1] == '\r')
1477 buf[strlen (buf) - 1] = 0;
1479 pwm->inquire_func = func;
1480 pwm->inquire_data = user;
1481 pwm->inquire_sent = 0;
1482 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1483 pwmd_free (buf);
1484 return rc;
1487 gpg_error_t
1488 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1489 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1491 va_list ap;
1493 if (result)
1494 *result = NULL;
1496 if (len)
1497 *len = 0;
1499 if (!pwm || !cmd)
1500 return FINISH (GPG_ERR_INV_ARG);
1501 if (!pwm->ctx)
1502 return FINISH (GPG_ERR_INV_STATE);
1504 va_start (ap, cmd);
1505 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1506 va_end (ap);
1507 return rc;
1510 static gpg_error_t
1511 send_pinentry_timeout (pwm_t *pwm)
1513 gpg_error_t rc = 0;
1515 if ((pwm->pinentry_timeout >= 0
1516 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1517 || (pwm->pinentry_timeout == -1
1518 && pwm->pinentry_timeout != pwm->current_pinentry_timeout))
1520 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1521 "OPTION pinentry-timeout=%i",
1522 pwm->pinentry_timeout);
1523 if (!rc)
1524 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1527 return rc;
1530 static gpg_error_t
1531 send_pinentry_options (pwm_t * pwm)
1533 gpg_error_t rc;
1535 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1536 "OPTION disable-pinentry=0");
1537 if (!rc && pwm->pinentry_tty)
1538 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1539 pwm->pinentry_tty);
1541 if (!rc && pwm->pinentry_term)
1542 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1543 pwm->pinentry_term);
1545 if (!rc && pwm->pinentry_display)
1546 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1547 pwm->pinentry_display);
1549 if (!rc && pwm->pinentry_desc)
1550 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1551 pwm->pinentry_desc);
1553 if (!rc && pwm->pinentry_lcctype)
1554 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1555 pwm->pinentry_lcctype);
1557 if (!rc && pwm->pinentry_lcmessages)
1558 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1559 pwm->pinentry_lcmessages);
1561 if (!rc)
1562 rc = send_pinentry_timeout (pwm);
1564 return rc;
1567 gpg_error_t
1568 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1570 if (!pwm || !result)
1571 return FINISH (GPG_ERR_INV_ARG);
1573 *result = PWMD_SOCKET_LOCAL;
1575 if (pwm->fd == ASSUAN_INVALID_FD)
1576 return FINISH (GPG_ERR_INV_STATE);
1578 if (pwm->user_fd != -1)
1580 *result = PWMD_SOCKET_USER;
1581 return 0;
1584 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1585 #ifdef WITH_SSH
1586 if (pwm->tcp && pwm->tcp->ssh)
1587 *result = PWMD_SOCKET_SSH;
1588 #endif
1589 #ifdef WITH_GNUTLS
1590 if (pwm->tcp && pwm->tcp->tls)
1591 *result = PWMD_SOCKET_TLS;
1592 #endif
1593 #endif
1594 return 0;
1597 static gpg_error_t
1598 disable_pinentry (pwm_t *pwm, int *disable)
1600 gpg_error_t rc;
1601 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1602 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1603 #else
1604 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1605 #endif
1607 if (disable)
1608 *disable = no_pinentry;
1610 if (pwm->pinentry_disabled && no_pinentry)
1611 return 0;
1612 else if (!pwm->pinentry_disabled && !no_pinentry)
1613 return 0;
1615 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1616 no_pinentry);
1617 if (!rc)
1618 pwm->pinentry_disabled = no_pinentry;
1620 return rc;
1623 gpg_error_t
1624 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1625 void *data)
1627 gpg_error_t rc = 0;
1628 int no_pinentry = 0;
1630 if (!pwm || !filename || !*filename)
1631 return FINISH (GPG_ERR_INV_ARG);
1633 if (!pwm->ctx)
1634 return FINISH (GPG_ERR_INV_STATE);
1636 command_start (pwm);
1637 rc = disable_pinentry (pwm, &no_pinentry);
1638 if (!rc && !no_pinentry)
1639 rc = send_pinentry_options (pwm);
1641 if (!rc)
1643 pwm->pinentry_try = 0;
1644 pwmd_free (pwm->filename);
1645 pwm->filename = pwmd_strdup (filename);
1649 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1650 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1651 filename);
1653 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1654 && pwm->pinentry_disabled
1655 && ++pwm->pinentry_try < pwm->pinentry_tries);
1657 pwm->pinentry_try = 0;
1659 if (rc)
1661 pwmd_free (pwm->filename);
1662 pwm->filename = NULL;
1666 pwmd_free (pwm->passphrase_hint);
1667 pwmd_free (pwm->passphrase_info);
1668 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1669 return FINISH (rc);
1672 static gpg_error_t
1673 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1674 void *data, int which)
1676 gpg_error_t rc = 0;
1677 int no_pinentry = 0;
1679 if (!pwm)
1680 return FINISH (GPG_ERR_INV_ARG);
1681 if (!pwm->ctx)
1682 return FINISH (GPG_ERR_INV_STATE);
1684 command_start (pwm);
1685 rc = disable_pinentry (pwm, &no_pinentry);
1686 if (!rc && !no_pinentry)
1687 rc = send_pinentry_options (pwm);
1689 if (!rc)
1691 if (which == PWMD_WHICH_SAVE)
1692 rc = pwmd_command (pwm, NULL, NULL, cb, data, "SAVE %s", args ? args : "");
1693 else if (which == PWMD_WHICH_PASSWD)
1694 rc = pwmd_command (pwm, NULL, NULL, cb, data, "PASSWD %s", args ? args : "");
1695 else if (which == PWMD_WHICH_GENKEY)
1696 rc = pwmd_command (pwm, NULL, NULL, cb, data, "GENKEY %s", args ? args : "");
1699 pwmd_free (pwm->passphrase_hint);
1700 pwmd_free (pwm->passphrase_info);
1701 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1702 return FINISH (rc);
1705 gpg_error_t
1706 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1708 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_PASSWD);
1711 gpg_error_t
1712 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1714 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_SAVE);
1717 gpg_error_t
1718 pwmd_genkey (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1720 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_GENKEY);
1723 static gpg_error_t
1724 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1726 int n, *intp;
1727 size_t *sizetp;
1728 char *arg1, **charpp;
1729 gpg_error_t rc = 0;
1731 if (!pwm)
1732 return GPG_ERR_INV_ARG;
1734 command_start (pwm);
1735 switch (opt)
1737 case PWMD_OPTION_SERVER_VERSION:
1738 if (!get)
1739 return GPG_ERR_NOT_SUPPORTED;
1741 if (!pwm->ctx)
1742 rc = GPG_ERR_INV_STATE;
1743 else
1745 unsigned *u = va_arg (ap, unsigned *);
1746 *u = pwm->version;
1749 break;
1750 case PWMD_OPTION_SIGPIPE:
1751 if (get)
1753 intp = va_arg (ap, int *);
1754 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1755 break;
1758 n = va_arg (ap, int);
1759 if (n < 0 || n > 1)
1761 rc = GPG_ERR_INV_VALUE;
1762 break;
1765 if (n)
1766 pwm->opts |= OPT_SIGPIPE;
1767 else
1768 pwm->opts &= ~OPT_SIGPIPE;
1770 break;
1771 case PWMD_OPTION_LOCK_ON_OPEN:
1772 if (get)
1774 intp = va_arg (ap, int *);
1775 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1776 break;
1779 n = va_arg (ap, int);
1780 if (n < 0 || n > 1)
1782 rc = GPG_ERR_INV_VALUE;
1783 break;
1786 if (n)
1787 pwm->opts |= OPT_LOCK_ON_OPEN;
1788 else
1789 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1791 break;
1792 case PWMD_OPTION_INQUIRE_TOTAL:
1793 if (get)
1795 sizetp = va_arg (ap, size_t *);
1796 *sizetp = pwm->inquire_total;
1797 break;
1800 pwm->inquire_total = va_arg (ap, size_t);
1801 break;
1802 case PWMD_OPTION_STATUS_CB:
1803 if (get)
1805 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1807 *cb = pwm->status_func;
1808 break;
1811 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1812 break;
1813 case PWMD_OPTION_STATUS_DATA:
1814 if (get)
1816 void **data = va_arg (ap, void **);
1818 *data = pwm->status_data;
1819 break;
1822 pwm->status_data = va_arg (ap, void *);
1823 break;
1824 case PWMD_OPTION_NO_PINENTRY:
1825 if (get)
1827 intp = va_arg (ap, int *);
1828 *intp = pwm->disable_pinentry;
1829 break;
1832 n = va_arg (ap, int);
1833 if (n < 0 || n > 1)
1834 rc = GPG_ERR_INV_VALUE;
1835 else
1836 pwm->disable_pinentry = n;
1837 break;
1838 case PWMD_OPTION_LOCAL_PINENTRY:
1839 if (get)
1841 intp = va_arg (ap, int *);
1842 *intp = pwm->local_pinentry;
1843 break;
1846 n = va_arg (ap, int);
1847 if (n < 0 || n > 1)
1848 rc = GPG_ERR_INV_VALUE;
1849 else
1850 pwm->local_pinentry = n;
1852 break;
1853 case PWMD_OPTION_PINENTRY_TIMEOUT:
1854 if (get)
1856 intp = va_arg (ap, int *);
1857 *intp = pwm->pinentry_timeout;
1858 break;
1861 n = va_arg (ap, int);
1862 if (n < 0)
1863 rc = GPG_ERR_INV_VALUE;
1864 else
1865 pwm->pinentry_timeout = n;
1866 break;
1867 case PWMD_OPTION_PINENTRY_TRIES:
1868 if (get)
1870 intp = va_arg (ap, int *);
1871 *intp = pwm->pinentry_tries;
1872 break;
1875 n = va_arg (ap, int);
1876 if (n < 0)
1877 rc = GPG_ERR_INV_VALUE;
1878 else
1879 pwm->pinentry_tries = n;
1880 break;
1881 case PWMD_OPTION_PINENTRY_PATH:
1882 if (get)
1884 charpp = va_arg (ap, char **);
1885 *charpp = pwm->pinentry_path;
1886 break;
1889 arg1 = va_arg (ap, char *);
1890 pwmd_free (pwm->pinentry_path);
1891 #ifdef __MINGW32__
1892 pwm->pinentry_path = arg1 ? pwmd_strdup (arg1) : NULL;
1893 #else
1894 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1895 #endif
1896 break;
1897 case PWMD_OPTION_PINENTRY_TTY:
1898 if (get)
1900 charpp = va_arg (ap, char **);
1901 *charpp = pwm->pinentry_tty;
1902 break;
1905 arg1 = va_arg (ap, char *);
1906 pwmd_free (pwm->pinentry_tty);
1907 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1908 break;
1909 case PWMD_OPTION_PINENTRY_DISPLAY:
1910 if (get)
1912 charpp = va_arg (ap, char **);
1913 *charpp = pwm->pinentry_display;
1914 break;
1917 arg1 = va_arg (ap, char *);
1918 pwmd_free (pwm->pinentry_display);
1919 pwm->pinentry_display = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
1920 #ifndef __MINGW32__
1921 if (!pwm->pinentry_display)
1922 unsetenv ("DISPLAY");
1923 #endif
1924 break;
1925 case PWMD_OPTION_PINENTRY_TERM:
1926 if (get)
1928 charpp = va_arg (ap, char **);
1929 *charpp = pwm->pinentry_term;
1930 break;
1933 arg1 = va_arg (ap, char *);
1934 pwmd_free (pwm->pinentry_term);
1935 pwm->pinentry_term = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
1936 #ifndef __MINGW32__
1937 if (pwm->pinentry_term)
1938 unsetenv ("TERM");
1939 #endif
1940 break;
1941 case PWMD_OPTION_PINENTRY_ERROR:
1942 if (get)
1944 charpp = va_arg (ap, char **);
1945 *charpp = pwm->pinentry_error;
1946 break;
1949 arg1 = va_arg (ap, char *);
1950 pwmd_free (pwm->pinentry_error);
1951 if (pwm->disable_pinentry)
1952 pwm->pinentry_error = arg1 ? pwmd_strdup (arg1) : NULL;
1953 else
1954 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1955 break;
1956 case PWMD_OPTION_PINENTRY_PROMPT:
1957 if (get)
1959 charpp = va_arg (ap, char **);
1960 *charpp = pwm->pinentry_prompt;
1961 break;
1964 arg1 = va_arg (ap, char *);
1965 pwmd_free (pwm->pinentry_prompt);
1966 if (pwm->disable_pinentry)
1967 pwm->pinentry_prompt = arg1 ? pwmd_strdup (arg1) : NULL;
1968 else
1969 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1970 break;
1971 case PWMD_OPTION_PINENTRY_DESC:
1972 if (get)
1974 charpp = va_arg (ap, char **);
1975 *charpp = pwm->pinentry_desc;
1976 break;
1979 arg1 = va_arg (ap, char *);
1980 pwmd_free (pwm->pinentry_desc);
1981 if (pwm->disable_pinentry)
1982 pwm->pinentry_desc = arg1 ? pwmd_strdup (arg1) : NULL;
1983 else
1984 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1985 break;
1986 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1987 if (get)
1989 charpp = va_arg (ap, char **);
1990 *charpp = pwm->pinentry_lcctype;
1991 break;
1994 arg1 = va_arg (ap, char *);
1995 pwmd_free (pwm->pinentry_lcctype);
1996 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1997 break;
1998 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1999 if (get)
2001 charpp = va_arg (ap, char **);
2002 *charpp = pwm->pinentry_lcmessages;
2003 break;
2006 arg1 = va_arg (ap, char *);
2007 pwmd_free (pwm->pinentry_lcmessages);
2008 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
2009 break;
2010 case PWMD_OPTION_KNOWNHOST_CB:
2011 if (get)
2013 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
2015 *cb = pwm->kh_cb;
2016 break;
2019 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
2020 break;
2021 case PWMD_OPTION_KNOWNHOST_DATA:
2022 if (get)
2024 void **data = va_arg (ap, void **);
2026 *data = pwm->kh_data;
2027 break;
2030 pwm->kh_data = va_arg (ap, void *);
2031 break;
2032 case PWMD_OPTION_SSH_AGENT:
2033 if (get)
2035 intp = va_arg (ap, int *);
2036 *intp = pwm->use_agent;
2037 break;
2040 n = va_arg (ap, int);
2041 if (n < 0 || n > 1)
2042 rc = GPG_ERR_INV_VALUE;
2043 else
2044 pwm->use_agent = n;
2045 break;
2046 case PWMD_OPTION_SSH_PASSPHRASE:
2047 if (get)
2048 return GPG_ERR_NOT_SUPPORTED;
2050 pwmd_free (pwm->ssh_passphrase);
2051 pwm->ssh_passphrase = NULL;
2052 arg1 = va_arg (ap, char *);
2053 if (arg1)
2055 pwm->ssh_passphrase = pwmd_strdup (arg1);
2056 if (!pwm->ssh_passphrase)
2057 return GPG_ERR_ENOMEM;
2059 break;
2060 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE:
2061 if (get)
2063 intp = va_arg (ap, int *);
2064 *intp = pwm->needs_passphrase;
2065 break;
2068 n = va_arg (ap, int);
2069 if (n < 0 || n > 1)
2070 rc = GPG_ERR_INV_VALUE;
2071 else
2072 pwm->needs_passphrase = n;
2073 break;
2074 case PWMD_OPTION_TLS_VERIFY:
2075 if (get)
2077 intp = va_arg (ap, int *);
2078 *intp = pwm->tls_verify;
2079 break;
2082 n = va_arg (ap, int);
2083 if (n < 0 || n > 1)
2084 rc = GPG_ERR_INV_VALUE;
2085 else
2086 pwm->tls_verify = n;
2087 break;
2088 case PWMD_OPTION_TLS_PRIORITY:
2089 if (get)
2091 charpp = va_arg (ap, char **);
2092 *charpp = pwm->tls_priority;
2093 break;
2096 pwmd_free (pwm->tls_priority);
2097 pwm->tls_priority = NULL;
2098 arg1 = va_arg (ap, char *);
2099 if (arg1)
2101 pwm->tls_priority = pwmd_strdup (arg1);
2102 if (!pwm->tls_priority)
2103 rc = GPG_ERR_ENOMEM;
2105 break;
2106 case PWMD_OPTION_SOCKET_TIMEOUT:
2107 if (get)
2109 intp = va_arg (ap, int *);
2110 *intp = pwm->socket_timeout;
2111 break;
2114 n = va_arg (ap, int);
2115 if (n < 0)
2117 rc = GPG_ERR_INV_VALUE;
2118 break;
2120 else
2121 pwm->socket_timeout = n;
2123 #ifdef WITH_SSH
2124 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
2126 pwm->tcp->ssh->timeout = pwm->socket_timeout;
2127 libssh2_session_set_timeout (pwm->tcp->ssh->session,
2128 pwm->socket_timeout * 1000);
2130 #endif
2131 #ifdef WITH_GNUTLS
2132 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
2133 pwm->tcp->tls->timeout = pwm->socket_timeout;
2134 #endif
2135 break;
2136 case PWMD_OPTION_READ_CB:
2137 if (get)
2139 pwmd_read_cb_t *cb = va_arg (ap, pwmd_read_cb_t *);
2141 *cb = pwm->read_cb;
2142 break;
2144 pwm->read_cb = va_arg (ap, pwmd_read_cb_t);
2145 break;
2146 case PWMD_OPTION_READ_CB_DATA:
2147 if (get)
2149 void **data = va_arg (ap, void **);
2151 *data = pwm->read_cb_data;
2152 break;
2155 pwm->read_cb_data = va_arg (ap, void *);
2156 break;
2157 case PWMD_OPTION_WRITE_CB:
2158 if (get)
2160 pwmd_write_cb_t *cb = va_arg (ap, pwmd_write_cb_t *);
2162 *cb = pwm->write_cb;
2163 break;
2165 pwm->write_cb = va_arg (ap, pwmd_write_cb_t);
2166 break;
2167 case PWMD_OPTION_WRITE_CB_DATA:
2168 if (get)
2170 void **data = va_arg (ap, void **);
2172 *data = pwm->write_cb_data;
2173 break;
2176 pwm->write_cb_data = va_arg (ap, void *);
2177 break;
2178 case PWMD_OPTION_OVERRIDE_INQUIRE:
2179 if (get)
2181 intp = va_arg (ap, int *);
2182 *intp = pwm->override_inquire;
2183 break;
2186 n = va_arg (ap, int);
2187 if (n < 0 || n > 1)
2188 rc = GPG_ERR_INV_VALUE;
2189 else
2190 pwm->override_inquire = n;
2191 break;
2192 default:
2193 rc = GPG_ERR_UNKNOWN_OPTION;
2194 break;
2197 return FINISH (rc);
2200 gpg_error_t
2201 pwmd_setopt (pwm_t * pwm, int opt, ...)
2203 va_list ap;
2204 gpg_error_t rc = 0;
2206 va_start (ap, opt);
2207 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
2208 va_end (ap);
2209 return FINISH (rc);
2212 gpg_error_t
2213 pwmd_getopt (pwm_t *pwm, int opt, ...)
2215 va_list ap;
2216 gpg_error_t rc = 0;
2218 va_start (ap, opt);
2219 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
2220 va_end (ap);
2221 return FINISH (rc);
2224 gpg_error_t
2225 set_rcdefaults (pwm_t *pwm, char *filename)
2227 char *f;
2228 FILE *fp;
2229 char *line = NULL, *p;
2230 unsigned line_n = 0;
2231 gpg_error_t rc = 0;
2233 #ifndef __MINGW32__
2234 if (!filename && isatty (STDIN_FILENO))
2236 char buf[256];
2237 int err = ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
2239 if (!err)
2241 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, buf);
2242 if (rc)
2243 return rc;
2245 if (getenv ("TERM"))
2247 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, getenv ("TERM"));
2248 if (rc)
2249 return rc;
2254 if (!filename && getenv ("DISPLAY"))
2256 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, getenv ("DISPLAY"));
2257 if (rc)
2258 return rc;
2260 #endif
2262 #ifdef __MINGW32__
2263 f = pwmd_strdup ("libpwmd.conf");
2264 #else
2265 f = _expand_homedir (filename ? filename : (char *)"~/.config/libpwmd.conf",
2266 NULL);
2267 #endif
2268 if (f)
2270 line = pwmd_malloc (LINE_MAX);
2271 if (line)
2273 fp = fopen (f, "r");
2274 if (!fp)
2276 pwmd_free (line);
2277 pwmd_free (f);
2278 return 0;
2281 else
2282 rc = GPG_ERR_ENOMEM;
2284 else
2285 rc = GPG_ERR_ENOMEM;
2287 if (rc)
2289 pwmd_free (f);
2290 pwmd_free (line);
2291 return rc;
2294 while ((p = fgets (line, LINE_MAX, fp)))
2296 char name[32] = {0}, val[512] = {0};
2297 char *np;
2298 char *t;
2299 size_t len = 0;
2301 line_n++;
2303 while (isspace (*p))
2304 p++;
2306 if (!*p || *p == '#')
2307 continue;
2309 if (p[strlen (p)-1] == '\n')
2310 p[strlen (p)-1] = 0;
2312 t = strchr (p, '=');
2313 if (!t)
2315 fprintf(stderr, N_("%s(%u): malformed line\n"), f, line_n);
2316 continue;
2319 for (np = name; p != t; p++)
2321 if (++len == sizeof (name))
2322 break;
2324 if (isspace (*p))
2325 break;
2327 *np++ = *p;
2330 while (isspace (*t))
2331 t++;
2332 t++; // '='
2333 while (isspace (*t))
2334 t++;
2336 strncpy (val, t, sizeof (val)-1);
2338 if (!strcasecmp (name, "pinentry-path"))
2339 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, val);
2340 else if (!strcasecmp (name, "pinentry-tries"))
2341 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, atoi (val));
2342 else if (!strcasecmp (name, "pinentry-timeout"))
2343 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, atoi (val));
2344 else if (!strcasecmp (name, "no-pinentry"))
2345 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, !!(atoi (val)));
2346 else if (!strcasecmp (name, "local-pinentry"))
2347 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, !!(atoi (val)));
2348 else if (!strcasecmp (name, "pinentry-display"))
2349 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, val);
2350 else if (!strcasecmp (name, "pinentry-ttyname"))
2351 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, val);
2352 else if (!strcasecmp (name, "pinentry-ttytype"))
2353 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, val);
2354 else if (!strcasecmp (name, "pinentry-lc-messages"))
2355 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, val);
2356 else if (!strcasecmp (name, "pinentry-lc-ctype"))
2357 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, val);
2358 else if (!strcasecmp (name, "no-ssh-agent"))
2359 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, !(atoi (val)));
2360 else if (!strcasecmp (name, "no-tls-verify"))
2361 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, !(atoi (val)));
2362 else if (!strcasecmp (name, "tls-priority"))
2363 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, val);
2364 else if (!strcasecmp (name, "socket-timeout"))
2365 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, atoi (val));
2366 else if (!strcasecmp (name, "no-lock"))
2367 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, !(atoi (val)));
2368 else if (!strcasecmp (name, "include"))
2369 rc = set_rcdefaults (pwm, val);
2370 else
2371 fprintf(stderr, N_("%s(%u): invalid option '%s', ignored.\n"), f,
2372 line_n, name);
2374 if (rc)
2375 break;
2378 fclose (fp);
2379 pwmd_free (line);
2380 pwmd_free (f);
2381 return rc;
2384 gpg_error_t
2385 pwmd_new (const char *name, pwm_t ** pwm)
2387 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
2388 gpg_error_t rc;
2390 if (!h)
2391 return FINISH (GPG_ERR_ENOMEM);
2393 if (name)
2395 h->name = pwmd_strdup (name);
2396 if (!h->name)
2398 pwmd_free (h);
2399 return FINISH (GPG_ERR_ENOMEM);
2403 reset_handle (h);
2404 h->pinentry_timeout = -1;
2405 h->current_pinentry_timeout = -1;
2406 h->pinentry_tries = 3;
2407 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2408 h->prot = PWMD_IP_ANY;
2409 h->socket_timeout = 120;
2410 h->tls_verify = 1;
2411 #ifdef __MINGW32__
2412 WSADATA wsdata;
2414 WSAStartup (0x202, &wsdata);
2415 #endif
2417 #endif
2418 h->opts |= OPT_LOCK_ON_OPEN;
2420 rc = set_rcdefaults (h, NULL);
2421 if (rc)
2422 goto fail;
2424 *pwm = h;
2425 return 0;
2427 fail:
2428 pwmd_close (h);
2429 return FINISH (rc);
2432 void
2433 pwmd_free (void *ptr)
2435 _xfree (ptr);
2438 void *
2439 pwmd_malloc (size_t size)
2441 return _xmalloc (size);
2444 void *
2445 pwmd_calloc (size_t nmemb, size_t size)
2447 return _xcalloc (nmemb, size);
2450 void *
2451 pwmd_realloc (void *ptr, size_t size)
2453 return _xrealloc (ptr, size);
2456 char *
2457 pwmd_strdup (const char *str)
2459 char *t;
2460 size_t len;
2461 register size_t c;
2463 len = strlen (str);
2464 t = _xmalloc ((len + 1) * sizeof (char));
2465 if (!t)
2466 return NULL;
2468 for (c = 0; c < len; c++)
2469 t[c] = str[c];
2471 t[c] = 0;
2472 return t;
2475 char *
2476 pwmd_strdup_printf (const char *fmt, ...)
2478 va_list ap, ap2;
2479 int len;
2480 char *buf;
2482 if (!fmt)
2483 return NULL;
2485 va_start (ap, fmt);
2486 va_copy (ap2, ap);
2487 len = vsnprintf (NULL, 0, fmt, ap);
2488 va_end (ap);
2489 buf = pwmd_malloc (++len);
2490 if (buf)
2491 vsnprintf (buf, len, fmt, ap2);
2493 va_end (ap2);
2494 return buf;
2497 gpg_error_t
2498 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
2499 size_t * len, pwmd_pinentry_t which)
2501 #ifndef WITH_PINENTRY
2502 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
2503 #else
2504 gpg_error_t rc;
2506 command_start (pwm);
2507 if (which == PWMD_PINENTRY_CONFIRM && pwm->disable_pinentry)
2509 rc = get_password (pwm, NULL, NULL, which, 1);
2510 return FINISH (rc);
2513 rc = _pwmd_getpin (pwm, filename, result, len, which);
2514 return FINISH (rc);
2515 #endif
2518 const char *
2519 pwmd_version ()
2521 return LIBPWMD_VERSION_STR;
2524 unsigned int
2525 pwmd_features ()
2527 unsigned int n = 0;
2529 #ifdef WITH_PINENTRY
2530 n |= PWMD_FEATURE_PINENTRY;
2531 #endif
2532 #ifdef WITH_SSH
2533 n |= PWMD_FEATURE_SSH;
2534 #endif
2535 #ifdef WITH_QUALITY
2536 n |= PWMD_FEATURE_QUALITY;
2537 #endif
2538 #ifdef WITH_GNUTLS
2539 n |= PWMD_FEATURE_GNUTLS;
2540 #endif
2541 return n;
2544 gpg_error_t
2545 pwmd_fd (pwm_t * pwm, int *fd)
2547 if (!pwm || !fd)
2548 return FINISH (GPG_ERR_INV_ARG);
2550 if (pwm->fd == ASSUAN_INVALID_FD)
2551 return FINISH (GPG_ERR_INV_STATE);
2553 *fd = HANDLE2SOCKET (pwm->fd);
2554 return 0;
2557 void
2558 pwmd_set_pointer (pwm_t *pwm, void *data)
2560 pwm->user_data = data;
2563 void *
2564 pwmd_get_pointer (pwm_t *pwm)
2566 return pwm->user_data;
2570 pwmd_gnutls_error (pwm_t *pwm, const char **str)
2572 #ifndef WITH_GNUTLS
2573 (void)pwm;
2574 (void)str;
2575 return 0;
2576 #else
2577 if (str && pwm && pwm->tls_error)
2578 *str = gnutls_strerror (pwm->tls_error);
2580 return pwm ? pwm->tls_error : 0;
2581 #endif
2584 gpg_error_t
2585 pwmd_cancel (pwm_t *pwm)
2587 if (!pwm)
2588 return FINISH (GPG_ERR_INV_ARG);
2590 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2591 if (pwm->fd == ASSUAN_INVALID_FD && !pwm->tcp)
2592 #else
2593 if (pwm->fd == ASSUAN_INVALID_FD)
2594 #endif
2595 return FINISH (GPG_ERR_INV_STATE);
2597 /* Can only cancel the connection for the time being. */
2598 if (pwm->connected)
2599 return FINISH (GPG_ERR_INV_STATE);
2601 pwm->cancel = 1;
2602 return 0;
2605 gpg_error_t
2606 pwmd_test_quality (const char *str, double *result)
2608 #ifndef WITH_QUALITY
2609 (void)str;
2610 (void)result;
2611 return GPG_ERR_NOT_IMPLEMENTED;
2612 #else
2613 if (!result)
2614 return GPG_ERR_INV_ARG;
2616 *result = ZxcvbnMatch (str, NULL, NULL);
2617 return 0;
2618 #endif