Update copyright header.
[libpwmd.git] / src / libpwmd.c
blob8ef7e0fd0b2535f43fc7c0f3a34665caf8d7ff7d
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 <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 enum
76 PWMD_WHICH_SAVE,
77 PWMD_WHICH_PASSWD,
78 PWMD_WHICH_GENKEY
81 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
82 ? gpg_error(rc) : rc
84 typedef struct
86 size_t len;
87 void *buf;
88 } membuf_t;
90 static gpg_error_t status_cb (void *data, const char *line);
92 ssize_t
93 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
95 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
96 pwm_t *pwm = assuan_get_pointer (ctx);
98 #ifdef WITH_SSH
99 if (pwm && pwm->tcp && pwm->tcp->ssh)
100 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
101 #endif
102 #ifdef WITH_GNUTLS
103 if (pwm && pwm->tcp && pwm->tcp->tls)
104 return tls_read_hook (pwm, fd, data, len);
105 #endif
106 #else
107 (void)ctx;
108 #endif
110 return read ((int) fd, data, len);
113 ssize_t
114 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
115 size_t len)
117 ssize_t wrote;
118 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
119 pwm_t *pwm = assuan_get_pointer (ctx);
121 #ifdef WITH_SSH
122 if (pwm && pwm->tcp && pwm->tcp->ssh)
123 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
124 #endif
125 #ifdef WITH_GNUTLS
126 if (pwm && pwm->tcp && pwm->tcp->tls)
127 return tls_write_hook (pwm, fd, data, len);
128 #endif
129 #else
130 (void)ctx;
131 #endif
133 /* libassuan cannot handle EAGAIN when doing writes. */
136 wrote = write ((int) fd, data, len);
137 if (wrote == -1 && errno == EAGAIN)
138 usleep (50000);
140 while (wrote == -1 && errno == EAGAIN);
142 return wrote;
145 pid_t
146 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
147 int options)
149 (void)ctx;
150 (void)action;
151 return waitpid (pid, status, options);
154 gpg_error_t
155 pwmd_init ()
157 static int initialized;
159 #ifdef WITH_GNUTLS
160 // May be called more than once.
161 gnutls_global_init ();
162 #endif
164 if (initialized)
165 return 0;
167 #ifdef ENABLE_NLS
168 bindtextdomain ("libpwmd", LOCALEDIR);
169 #endif
170 #ifdef WITH_SSH
171 libssh2_init (0);
172 #endif
173 gpgrt_init ();
174 //gpgrt_set_alloc_func (_xrealloc_gpgrt);
176 #ifdef WITH_QUALITY
177 ZxcvbnInit (NULL);
178 #endif
180 initialized = 1;
181 return 0;
184 void
185 pwmd_deinit ()
187 #ifdef WITH_GNUTLS
188 gnutls_global_deinit ();
189 #endif
190 #ifdef WITH_QUALITY
191 ZxcvbnUnInit();
192 #endif
195 gpg_error_t
196 _connect_finalize (pwm_t * pwm)
198 gpg_error_t rc = 0;
199 char *result = NULL;
200 int active[2];
201 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
203 if (n <= 0)
204 return GPG_ERR_EBADFD;
206 pwm->fd = active[0];
207 #ifdef WITH_PINENTRY
208 pwm->pinentry_pid = -1;
209 #endif
211 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "GETINFO VERSION");
212 if (!rc)
214 pwm->version = strtoul (result, NULL, 16);
215 pwmd_free (result);
218 if (!rc && pwm->name)
219 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
220 pwm->name);
222 return rc;
225 static gpg_error_t
226 connect_uds (pwm_t * pwm, const char *path)
228 char *socketpath = NULL;
229 struct passwd pw;
230 char *pwbuf;
231 gpg_error_t rc;
233 if (!pwm)
234 return GPG_ERR_INV_ARG;
236 pwbuf = _getpwuid (&pw);
237 if (!pwbuf)
238 return gpg_error_from_syserror ();
240 if (!path || !*path)
241 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
242 else
243 socketpath = _expand_homedir ((char *) path, &pw);
245 pwmd_free (pwbuf);
246 if (!socketpath)
247 return GPG_ERR_ENOMEM;
249 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
250 pwmd_free (socketpath);
251 return rc ? rc : _connect_finalize (pwm);
254 static gpg_error_t
255 init_handle (pwm_t * pwm)
257 gpg_error_t rc;
258 static struct assuan_malloc_hooks mhooks = {
259 pwmd_malloc, pwmd_realloc, pwmd_free
261 static struct assuan_system_hooks shooks = {
262 ASSUAN_SYSTEM_HOOKS_VERSION,
263 __assuan_usleep,
264 __assuan_pipe,
265 __assuan_close,
266 hook_read,
267 hook_write,
268 //FIXME
269 NULL, //recvmsg
270 NULL, //sendmsg both are used for FD passing
271 __assuan_spawn,
272 hook_waitpid,
273 __assuan_socketpair,
274 __assuan_socket,
275 __assuan_connect
278 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
279 NULL);
280 if (rc)
281 return rc;
283 assuan_set_pointer (pwm->ctx, pwm);
284 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
285 return 0;
288 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
289 void
290 free_tcp (pwm_t *pwm)
292 struct tcp_s *tcp = pwm->tcp;
294 if (!tcp)
295 return;
297 #ifdef WITH_SSH
298 _free_ssh_conn (tcp->ssh);
299 #endif
300 #ifdef WITH_GNUTLS
301 tls_free (pwm);
302 #endif
304 pwmd_free (tcp->host);
305 if (tcp->addrs)
307 freeaddrinfo (tcp->addrs);
308 tcp->addrs = NULL;
311 pthread_cond_destroy (&tcp->dns_cond);
312 pthread_mutex_destroy (&tcp->dns_mutex);
313 pwmd_free (tcp);
314 pwm->tcp = NULL;
316 #endif
318 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
319 static void *
320 resolve_host_thread (void *arg)
322 pwm_t *pwm = arg;
323 struct addrinfo hints = { 0 };
324 char portstr[6];
326 switch (pwm->prot)
328 case PWMD_IP_ANY:
329 hints.ai_family = AF_UNSPEC;
330 break;
331 case PWMD_IPV4:
332 hints.ai_family = AF_INET;
333 break;
334 case PWMD_IPV6:
335 hints.ai_family = AF_INET6;
336 break;
339 hints.ai_socktype = SOCK_STREAM;
340 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
341 int *n = pwmd_malloc (sizeof (int));
342 pthread_cleanup_push (pwmd_free, n);
343 *n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
344 pthread_cleanup_pop (0);
345 pthread_cond_broadcast (&pwm->tcp->dns_cond);
346 pthread_exit (n);
347 return NULL;
350 gpg_error_t
351 tcp_connect_common (pwm_t * pwm)
353 #define TS_TIMEOUT 50000000L
354 int n;
355 gpg_error_t rc = 0;
356 pthread_t tid;
357 time_t now;
359 time (&now);
360 n = pthread_create (&tid, NULL, resolve_host_thread, pwm);
361 if (n)
362 return gpg_error_from_errno (n);
364 pthread_mutex_lock (&pwm->tcp->dns_mutex);
366 for (;;)
368 struct timespec ts;
369 int *result = NULL;
371 clock_gettime (CLOCK_REALTIME, &ts);
372 if (ts.tv_nsec + TS_TIMEOUT >= 1000000000LL) {
373 ts.tv_sec++;
374 ts.tv_nsec = 0;
376 else
377 ts.tv_nsec += TS_TIMEOUT;
379 if (pwm->cancel)
381 #ifdef HAVE_PTHREAD_CANCEL
382 pthread_cancel (tid);
383 pthread_join (tid, NULL);
384 #else
385 pthread_join (tid, (void **)&result);
386 pwmd_free (result);
387 #endif
388 return GPG_ERR_CANCELED;
391 n = pthread_cond_timedwait (&pwm->tcp->dns_cond, &pwm->tcp->dns_mutex,
392 &ts);
393 if (n == ETIMEDOUT)
395 if (pwm->socket_timeout && ts.tv_sec - now >= pwm->socket_timeout)
397 #ifdef HAVE_PTHREAD_CANCEL
398 pthread_cancel (tid);
399 pthread_join (tid, NULL);
400 #else
401 pthread_join (tid, (void **)&result);
402 pwmd_free (result);
403 #endif
404 return GPG_ERR_ETIMEDOUT;
407 continue;
409 else if (n)
411 #ifdef HAVE_PTHREAD_CANCEL
412 pthread_cancel (tid);
413 pthread_join (tid, NULL);
414 #else
415 pthread_join (tid, (void **)&result);
416 pwmd_free (result);
417 #endif
418 return gpg_error_from_errno (n);
421 pthread_join (tid, (void **)&result);
422 n = *result;
423 pwmd_free (result);
424 break;
427 if (n)
428 return GPG_ERR_UNKNOWN_HOST; //FIXME
430 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
431 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
433 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
434 if (pwm->fd == -1)
436 rc = gpg_error_from_syserror ();
437 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
438 break;
439 continue;
442 if (fcntl (pwm->fd, F_SETFL, O_NONBLOCK) == -1)
444 rc = gpg_error_from_syserror ();
445 break;
448 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
449 pwm->tcp->addr->ai_family == AF_INET6
450 ? sizeof (struct sockaddr_in6)
451 : sizeof (struct sockaddr)) == -1)
453 struct timeval tv;
454 fd_set wfds;
455 unsigned elapsed = 0;
457 rc = gpg_error_from_syserror ();
458 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
460 close (pwm->fd);
461 pwm->fd = -1;
462 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
463 return rc;
464 continue;
467 again:
468 tv.tv_sec = 1;
469 tv.tv_usec = 0;
470 FD_ZERO (&wfds);
471 FD_SET (pwm->fd, &wfds);
472 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
473 rc = 0;
474 if (!n || pwm->cancel)
476 if (pwm->cancel)
477 rc = gpg_error (GPG_ERR_CANCELED);
478 else if (++elapsed >= pwm->socket_timeout)
479 rc = gpg_error (GPG_ERR_ETIMEDOUT);
480 else
481 goto again;
483 else if (n != -1)
485 socklen_t len = sizeof(int);
487 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
488 if (n)
489 rc = gpg_error_from_errno (n);
491 else if (n == -1)
492 rc = gpg_error_from_syserror ();
494 if (rc)
496 close (pwm->fd);
497 pwm->fd = -1;
498 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
499 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
500 || pwm->cancel)
501 return rc;
503 else
504 break;
506 else
507 break;
510 if (!rc)
511 if (fcntl (pwm->fd, F_SETFL, 0) == -1)
512 rc = gpg_error_from_syserror ();
514 return rc;
516 #endif
518 static void
519 command_start (pwm_t *pwm)
521 pwm->cancel = 0;
524 gpg_error_t
525 pwmd_connect (pwm_t * pwm, const char *url, ...)
527 const char *p = url;
528 gpg_error_t rc;
530 if (!pwm)
531 return FINISH (GPG_ERR_INV_ARG);
532 else if (!pwm->ctx)
534 rc = init_handle (pwm);
535 if (rc)
536 return rc;
539 command_start (pwm);
541 if (!(pwm->opts & OPT_SIGPIPE))
542 signal (SIGPIPE, SIG_IGN);
544 #ifdef WITH_GNUTLS
545 pwm->tls_error = 0;
546 #endif
547 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
549 if (p && (*p == '/' || *p == '~'))
550 rc = connect_uds (pwm, p);
551 else if (!p || !strncmp (p, "file://", 7))
553 if (p)
554 p += 7;
555 #ifdef DEFAULT_PWMD_SOCKET
556 else
557 p = DEFAULT_PWMD_SOCKET;
558 #endif
559 rc = connect_uds (pwm, p);
561 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
562 !strncmp (p, "ssh4://", 7))
564 #ifndef WITH_SSH
565 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
566 #else
567 char *host = NULL;
568 int port;
569 char *username = NULL;
571 if (!strncmp (p, "ssh6://", 7))
573 pwm->prot = PWMD_IPV6;
574 p += 7;
576 else if (!strncmp (p, "ssh4://", 7))
578 pwm->prot = PWMD_IPV4;
579 p += 7;
581 else
583 pwm->prot = PWMD_IP_ANY;
584 p += 6;
587 rc = _parse_ssh_url (p, &host, &port, &username);
588 if (!rc)
590 va_list ap;
591 char *identity = NULL;
592 char *knownhosts = NULL;
594 va_start (ap, url);
595 identity = va_arg (ap, char *);
597 if (!identity && !pwm->use_agent)
598 rc = GPG_ERR_INV_ARG;
599 else
600 knownhosts = va_arg (ap, char *);
602 va_end (ap);
604 if (!rc)
605 rc = _do_ssh_connect (pwm, host, port, identity, username,
606 knownhosts);
607 if (!rc)
609 rc = _connect_finalize (pwm);
610 if (rc)
611 free_tcp (pwm);
615 pwmd_free (host);
616 pwmd_free (username);
617 pwm->local_pinentry = 1;
618 pwmd_free (pwm->ssh_passphrase);
619 pwm->ssh_passphrase = NULL;
620 #endif
622 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
623 !strncmp (p, "tls4://", 7))
625 #ifndef WITH_GNUTLS
626 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
627 #else
628 char *host = NULL;
629 int port;
631 if (!strncmp (p, "tls6://", 7))
633 pwm->prot = PWMD_IPV6;
634 p += 7;
636 else if (!strncmp (p, "tls4://", 7))
638 pwm->prot = PWMD_IPV4;
639 p += 7;
641 else
643 pwm->prot = PWMD_IP_ANY;
644 p += 6;
647 rc = tls_parse_url (p, &host, &port);
648 if (!rc)
650 va_list ap;
651 char *clientcert = NULL;
652 char *clientkey = NULL;
653 char *cacert = NULL;
654 char *server_fp = NULL;
656 va_start (ap, url);
657 clientcert = va_arg (ap, char *);
659 if (!clientcert)
660 rc = GPG_ERR_INV_ARG;
661 else
663 clientkey = va_arg (ap, char *);
664 if (!clientkey)
665 rc = GPG_ERR_INV_ARG;
666 else
668 cacert = va_arg (ap, char *);
669 if (!cacert)
670 rc = GPG_ERR_INV_ARG;
671 else
672 server_fp = va_arg (ap, char *);
676 va_end (ap);
678 if (!rc)
679 rc = tls_connect (pwm, host, port, clientcert, clientkey, cacert,
680 pwm->tls_priority, server_fp, pwm->tls_verify);
681 if (!rc)
683 rc = _connect_finalize (pwm);
684 if (rc)
685 free_tcp (pwm);
689 pwmd_free (host);
690 pwm->local_pinentry = 1;
691 #endif
694 if (!rc)
695 pwm->connected = 1;
697 return FINISH (rc);
700 static void
701 disconnect (pwm_t * pwm)
703 if (!pwm)
704 return;
706 if (pwm->ctx)
707 assuan_release (pwm->ctx);
709 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
710 free_tcp (pwm);
711 #endif
712 pwm->ctx = NULL;
713 pwm->fd = -1;
714 pwm->connected = 0;
717 void
718 pwmd_close (pwm_t * pwm)
720 if (!pwm)
721 return;
723 disconnect (pwm);
724 pwmd_free (pwm->pinentry_error);
725 pwmd_free (pwm->pinentry_desc);
726 pwmd_free (pwm->pinentry_prompt);
727 pwmd_free (pwm->pinentry_tty);
728 pwmd_free (pwm->pinentry_display);
729 pwmd_free (pwm->pinentry_term);
730 pwmd_free (pwm->pinentry_lcctype);
731 pwmd_free (pwm->pinentry_lcmessages);
732 pwmd_free (pwm->filename);
733 pwmd_free (pwm->name);
734 pwmd_free (pwm->passphrase_info);
735 pwmd_free (pwm->passphrase_hint);
736 pwmd_free (pwm->ssh_passphrase);
737 pwmd_free (pwm->tls_priority);
739 #ifdef WITH_PINENTRY
740 if (pwm->pctx)
741 _pinentry_disconnect (pwm);
742 #endif
744 pwmd_free (pwm);
747 static gpg_error_t
748 inquire_realloc_cb (void *data, const void *buffer, size_t len)
750 membuf_t *mem = (membuf_t *) data;
751 void *p;
753 if (!buffer)
754 return 0;
756 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
757 return gpg_error (GPG_ERR_ENOMEM);
759 mem->buf = p;
760 memcpy ((char *) mem->buf + mem->len, buffer, len);
761 mem->len += len;
762 return 0;
765 static gpg_error_t
766 get_password (pwm_t * pwm, char **result, size_t * len,
767 pwmd_pinentry_t w, int echo)
769 char buf[ASSUAN_LINELENGTH+1] = { 0 }, *p;
770 struct termios told, tnew;
771 char *key = NULL;
773 if (result)
774 *result = NULL;
776 if (len)
777 *len = 0;
779 if (!isatty (STDIN_FILENO))
781 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
782 return GPG_ERR_ENOTTY;
785 if (!echo)
787 if (tcgetattr (STDIN_FILENO, &told) == -1)
788 return gpg_error_from_syserror ();
790 memcpy (&tnew, &told, sizeof (struct termios));
791 tnew.c_lflag &= ~(ECHO);
792 tnew.c_lflag |= ICANON | ECHONL;
794 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
796 int n = errno;
798 tcsetattr (STDIN_FILENO, TCSANOW, &told);
799 return gpg_error_from_errno (n);
803 if (pwm->passphrase_hint)
804 fprintf(stderr, N_("Key info: %s\n"), pwm->passphrase_hint);
806 switch (w)
808 case PWMD_PINENTRY_OPEN:
809 fprintf (stderr, N_("Passphrase for %s: "), pwm->filename);
810 break;
811 case PWMD_PINENTRY_OPEN_FAILED:
812 fprintf (stderr, N_("Invalid passphrase. Passphrase for %s: "),
813 pwm->filename);
814 break;
815 case PWMD_PINENTRY_SAVE:
816 fprintf (stderr, N_("New passphrase for %s: "), pwm->filename);
817 break;
818 case PWMD_PINENTRY_SAVE_CONFIRM:
819 fprintf (stderr, N_("Repeat passphrase: "));
820 break;
821 case PWMD_PINENTRY_CONFIRM:
822 if (pwm->pinentry_desc)
823 fprintf (stderr, "%s", pwm->pinentry_desc);
825 if (pwm->pinentry_prompt)
826 fprintf (stderr, "%s", pwm->pinentry_prompt);
827 else
828 fprintf(stderr, N_("Confirm [y/N]:"));
829 default:
830 break;
833 p = fgets (buf, sizeof (buf), stdin);
835 if (!echo)
836 tcsetattr (STDIN_FILENO, TCSANOW, &told);
838 if (!p || feof (stdin))
840 clearerr (stdin);
841 return GPG_ERR_CANCELED;
844 /* Strip the newline character. */
845 p[strlen (p) - 1] = 0;
847 if (buf[0])
849 if (w == PWMD_PINENTRY_CONFIRM)
851 if (*p != 'y' && *p != 'Y')
852 return GPG_ERR_CANCELED;
853 return 0;
856 key = pwmd_strdup_printf ("%s", p);
857 wipememory (buf, 0, sizeof (buf));
858 if (!key)
859 return GPG_ERR_ENOMEM;
861 if (result)
862 *result = key;
864 if (len)
865 *len = strlen (key);
867 else
869 if (w == PWMD_PINENTRY_CONFIRM)
870 return GPG_ERR_CANCELED;
872 /* To satisfy inquire_cb(). */
873 if (result)
874 *result = pwmd_strdup ("");
876 if (len)
877 *len = 1;
880 return 0;
883 gpg_error_t
884 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
886 gpg_error_t rc;
887 int new_password = 0;
888 char *password = NULL, *newpass = NULL;
889 int error = 0;
891 command_start (pwm);
893 if (data)
894 *data = NULL;
896 if (size)
897 *size = 0;
899 if (!strcmp (keyword, "NEW_PASSPHRASE"))
900 new_password = 1;
902 if (!new_password && pwm->pinentry_try)
903 error = 1;
905 again:
906 if (pwm->disable_pinentry)
908 rc = get_password (pwm, &password, size,
909 new_password ? PWMD_PINENTRY_SAVE :
910 error ? PWMD_PINENTRY_OPEN_FAILED :
911 PWMD_PINENTRY_OPEN, 0);
912 if (!rc && new_password)
913 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
916 else
918 pwmd_pinentry_t which;
920 if (error)
921 which = new_password
922 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
923 else
924 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
926 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
927 if (!rc && new_password)
928 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
929 PWMD_PINENTRY_SAVE_CONFIRM);
932 if (!rc && new_password)
934 if ((!password && newpass) || (!newpass && password)
935 || (newpass && password && strcmp (newpass, password)))
937 if (pwm->disable_pinentry)
938 fprintf (stderr, N_("Passphrases do not match.\n"));
940 pwmd_free (password);
941 pwmd_free (newpass);
942 password = newpass = NULL;
943 error = 1;
944 goto again;
948 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
949 pwmd_free (newpass);
950 if (!rc && data)
951 *data = password;
952 else
953 pwmd_free (password);
955 return rc;
958 static gpg_error_t
959 inquire_cb (void *data, const char *keyword)
961 pwm_t *pwm = (pwm_t *) data;
962 gpg_error_t rc = 0;
963 int free_result = 0;
964 char *result = NULL;
965 int is_password = 0;
966 int new_password = 0;
968 if (!strcmp (keyword, "PASSPHRASE") || !strcmp (keyword, "SIGN_PASSPHRASE"))
969 is_password = 1;
970 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
971 new_password = 1;
973 /* Shouldn't get this far without a callback. */
974 if (!pwm->override_inquire && !pwm->inquire_func
975 && !is_password && !new_password)
976 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
978 for (;;)
980 size_t len = 0;
981 gpg_error_t arc;
983 result = NULL;
985 if (!pwm->override_inquire && (is_password || new_password))
987 free_result = 1;
988 rc = pwmd_password (data, keyword, &result, &len);
989 if (!rc)
990 rc = GPG_ERR_EOF;
992 else
993 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
994 &len);
996 /* gpg will truncate a passphrase at the first nil byte which may be bad
997 * for generated key files. */
998 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
999 && (is_password || new_password))
1001 if (len && result && *result)
1003 for (size_t n = 0; n < len; n++)
1005 if (result[n] == 0 && n+1 != len)
1006 rc = GPG_ERR_INV_PASSPHRASE;
1011 cancel:
1012 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
1014 #ifndef LIBASSUAN_2_1_0
1015 gpg_error_t trc = rc;
1017 /* Cancel this inquire. */
1018 rc = assuan_send_data (pwm->ctx, NULL, 1);
1019 if (!rc)
1021 char *line;
1022 size_t len;
1024 /* There is a bug (or feature?) in assuan_send_data() that
1025 * when cancelling an inquire the next read from the server is
1026 * not done until the next command making the next command
1027 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
1029 rc = assuan_read_line (pwm->ctx, &line, &len);
1031 /* Restore the original error. This differs from the error
1032 * returned from the pwmd command (GPG_ERR_CANCELED). This
1033 * error is returned to the calling function.
1035 if (!rc)
1036 rc = trc;
1038 #endif
1039 break;
1042 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
1044 if (len <= 0 && !result)
1046 rc = 0;
1047 break;
1049 else if ((len <= 0 && result) || (len && !result))
1051 rc = gpg_error (GPG_ERR_INV_ARG);
1052 break;
1055 if (pwm->inquire_maxlen
1056 && pwm->inquire_sent + len > pwm->inquire_maxlen)
1058 rc = gpg_error (GPG_ERR_TOO_LARGE);
1059 if (!free_result)
1060 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
1061 &result, &len);
1062 goto cancel;
1065 arc = assuan_send_data (pwm->ctx, result, len);
1066 if (gpg_err_code (rc) == GPG_ERR_EOF)
1068 rc = arc;
1069 break;
1072 rc = arc;
1074 else if (rc)
1075 break;
1077 if (!rc)
1079 pwm->inquire_sent += len;
1081 if (pwm->status_func)
1083 char buf[ASSUAN_LINELENGTH];
1085 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
1086 pwm->inquire_total);
1087 rc = pwm->status_func (pwm->status_data, buf);
1088 if (rc)
1089 continue;
1094 if (free_result)
1095 pwmd_free (result);
1097 pwm->inquire_maxlen = pwm->inquire_sent = 0;
1098 return rc;
1101 static gpg_error_t
1102 parse_assuan_line (pwm_t * pwm)
1104 gpg_error_t rc;
1105 char *line;
1106 size_t len;
1108 rc = assuan_read_line (pwm->ctx, &line, &len);
1109 if (!rc)
1111 if (line[0] == 'O' && line[1] == 'K' &&
1112 (line[2] == 0 || line[2] == ' '))
1115 else if (line[0] == '#')
1118 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
1120 rc = status_cb (pwm, line[1] == 0 ? line + 1 : line + 2);
1122 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
1123 (line[3] == 0 || line[3] == ' '))
1125 line += 4;
1126 rc = strtol (line, NULL, 10);
1130 return rc;
1133 static void
1134 reset_handle (pwm_t *pwm)
1136 pwm->fd = -1;
1137 pwm->cancel = 0;
1138 pwm->pinentry_disabled = 0;
1139 #ifdef WITH_PINENTRY
1140 if (pwm->pctx)
1141 _pinentry_disconnect (pwm);
1142 #endif
1143 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1144 #ifdef WITH_GNUTLS
1145 pwm->tls_error = 0;
1146 #endif
1148 if (pwm->tcp)
1149 pwm->tcp->rc = 0;
1150 #endif
1153 gpg_error_t
1154 pwmd_disconnect (pwm_t * pwm)
1156 if (!pwm)
1157 return FINISH (GPG_ERR_INV_ARG);
1159 command_start (pwm);
1161 if (pwm->fd == -1)
1162 return FINISH (GPG_ERR_INV_STATE);
1164 disconnect (pwm);
1165 reset_handle (pwm);
1166 return 0;
1169 /* Note that this should only be called when not in a command. */
1170 gpg_error_t
1171 pwmd_process (pwm_t * pwm)
1173 gpg_error_t rc = 0;
1174 fd_set fds;
1175 struct timeval tv = { 0, 0 };
1176 int n;
1178 if (!pwm || pwm->fd == -1)
1179 return FINISH (GPG_ERR_INV_ARG);
1180 else if (!pwm->ctx)
1181 return FINISH (GPG_ERR_INV_STATE);
1183 FD_ZERO (&fds);
1184 FD_SET (pwm->fd, &fds);
1185 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1187 if (n == -1)
1188 return FINISH (gpg_error_from_syserror ());
1190 if (n > 0)
1192 if (FD_ISSET (pwm->fd, &fds))
1193 rc = parse_assuan_line (pwm);
1196 while (!rc && assuan_pending_line (pwm->ctx))
1197 rc = parse_assuan_line (pwm);
1199 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1200 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1202 close (pwm->fd);
1203 pwm->fd = -1;
1205 #endif
1207 return FINISH (rc);
1210 static gpg_error_t
1211 status_cb (void *data, const char *line)
1213 pwm_t *pwm = data;
1215 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1216 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1217 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1219 pwmd_free (pwm->passphrase_hint);
1220 pwm->passphrase_hint = pwmd_strdup (line+16);
1222 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1224 pwmd_free (pwm->passphrase_info);
1225 pwm->passphrase_info = pwmd_strdup (line+16);
1227 #ifdef WITH_GNUTLS
1228 else if (!strcmp (line, "REHANDSHAKE"))
1230 char buf[32];
1231 ssize_t ret;
1233 ret = tls_read_hook (pwm, pwm->fd, buf, sizeof (buf));
1234 if (ret < 0)
1236 pwm->tls_error = ret;
1237 return GPG_ERR_GENERAL;
1240 #endif
1242 if (pwm->status_func)
1243 return pwm->status_func (pwm->status_data, line);
1245 return 0;
1248 gpg_error_t
1249 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1250 char **result, size_t * len, const char *cmd)
1252 membuf_t data;
1253 gpg_error_t rc;
1255 if (!cmd || !*cmd)
1256 return FINISH (GPG_ERR_INV_ARG);
1258 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1259 return FINISH (GPG_ERR_LINE_TOO_LONG);
1261 data.len = 0;
1262 data.buf = NULL;
1263 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1264 #ifdef WITH_QUALITY
1265 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1266 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1267 #else
1268 inquire_cb, pwm,
1269 #endif
1270 status_cb, pwm);
1272 if (rc)
1274 if (data.buf)
1276 pwmd_free (data.buf);
1277 data.buf = NULL;
1280 else
1282 if (data.buf)
1284 inquire_realloc_cb (&data, "", 1);
1286 if (result)
1287 *result = (char *) data.buf;
1288 else
1289 pwmd_free (data.buf);
1291 if (len)
1292 *len = data.len;
1296 pwm->inquire_maxlen = 0;
1297 return rc;
1300 gpg_error_t
1301 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1302 pwmd_inquire_cb_t func, void *user, const char *cmd,
1303 va_list ap)
1305 char *buf;
1306 size_t len;
1307 va_list ap2;
1309 if (!pwm)
1310 return GPG_ERR_INV_ARG;
1312 command_start (pwm);
1314 if (result)
1315 *result = NULL;
1317 if (rlen)
1318 *rlen = 0;
1320 if (!pwm || !cmd)
1321 return FINISH (GPG_ERR_INV_ARG);
1322 if (!pwm->ctx)
1323 return FINISH (GPG_ERR_INV_STATE);
1326 * C99 allows the dst pointer to be null which will calculate the length
1327 * of the would-be result and return it.
1329 va_copy (ap2, ap);
1330 len = vsnprintf (NULL, 0, cmd, ap);
1331 buf = (char *) pwmd_malloc (len+1);
1332 if (!buf)
1334 va_end (ap2);
1335 return FINISH (GPG_ERR_ENOMEM);
1338 if (vsnprintf (buf, len+1, cmd, ap2) != len)
1340 pwmd_free (buf);
1341 va_end (ap2);
1342 return FINISH (GPG_ERR_ENOMEM);
1345 if (buf[strlen (buf) - 1] == '\n')
1346 buf[strlen (buf) - 1] = 0;
1347 if (buf[strlen (buf) - 1] == '\r')
1348 buf[strlen (buf) - 1] = 0;
1350 pwm->inquire_func = func;
1351 pwm->inquire_data = user;
1352 pwm->inquire_sent = 0;
1353 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1354 pwmd_free (buf);
1355 return rc;
1358 gpg_error_t
1359 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1360 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1362 va_list ap;
1364 if (result)
1365 *result = NULL;
1367 if (len)
1368 *len = 0;
1370 if (!pwm || !cmd)
1371 return FINISH (GPG_ERR_INV_ARG);
1372 if (!pwm->ctx)
1373 return FINISH (GPG_ERR_INV_STATE);
1375 va_start (ap, cmd);
1376 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1377 va_end (ap);
1378 return rc;
1381 static gpg_error_t
1382 send_pinentry_timeout (pwm_t *pwm)
1384 gpg_error_t rc = 0;
1386 if ((pwm->pinentry_timeout >= 0
1387 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1388 || (pwm->pinentry_timeout == -1
1389 && pwm->pinentry_timeout != pwm->current_pinentry_timeout))
1391 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1392 "OPTION pinentry-timeout=%i",
1393 pwm->pinentry_timeout);
1394 if (!rc)
1395 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1398 return rc;
1401 static gpg_error_t
1402 send_pinentry_options (pwm_t * pwm)
1404 gpg_error_t rc;
1406 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1407 "OPTION disable-pinentry=0");
1408 if (!rc && pwm->pinentry_tty)
1409 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1410 pwm->pinentry_tty);
1412 if (!rc && pwm->pinentry_term)
1413 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1414 pwm->pinentry_term);
1416 if (!rc && pwm->pinentry_display)
1417 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1418 pwm->pinentry_display);
1420 if (!rc && pwm->pinentry_desc)
1421 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1422 pwm->pinentry_desc);
1424 if (!rc && pwm->pinentry_lcctype)
1425 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1426 pwm->pinentry_lcctype);
1428 if (!rc && pwm->pinentry_lcmessages)
1429 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1430 pwm->pinentry_lcmessages);
1432 if (!rc)
1433 rc = send_pinentry_timeout (pwm);
1435 return rc;
1438 gpg_error_t
1439 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1441 if (!pwm || !result)
1442 return FINISH (GPG_ERR_INV_ARG);
1444 *result = PWMD_SOCKET_LOCAL;
1446 if (pwm->fd == -1)
1447 return FINISH (GPG_ERR_INV_STATE);
1449 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1450 #ifdef WITH_SSH
1451 if (pwm->tcp && pwm->tcp->ssh)
1452 *result = PWMD_SOCKET_SSH;
1453 #endif
1454 #ifdef WITH_GNUTLS
1455 if (pwm->tcp && pwm->tcp->tls)
1456 *result = PWMD_SOCKET_TLS;
1457 #endif
1458 #endif
1459 return 0;
1462 static gpg_error_t
1463 disable_pinentry (pwm_t *pwm, int *disable)
1465 gpg_error_t rc;
1466 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1467 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1468 #else
1469 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1470 #endif
1472 if (disable)
1473 *disable = no_pinentry;
1475 if (pwm->pinentry_disabled && no_pinentry)
1476 return 0;
1477 else if (!pwm->pinentry_disabled && !no_pinentry)
1478 return 0;
1480 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1481 no_pinentry);
1482 if (!rc)
1483 pwm->pinentry_disabled = no_pinentry;
1485 return rc;
1488 gpg_error_t
1489 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1490 void *data)
1492 gpg_error_t rc = 0;
1493 int no_pinentry = 0;
1495 if (!pwm || !filename || !*filename)
1496 return FINISH (GPG_ERR_INV_ARG);
1498 if (!pwm->ctx)
1499 return FINISH (GPG_ERR_INV_STATE);
1501 command_start (pwm);
1502 rc = disable_pinentry (pwm, &no_pinentry);
1503 if (!rc && !no_pinentry)
1504 rc = send_pinentry_options (pwm);
1506 if (!rc)
1508 pwm->pinentry_try = 0;
1509 pwmd_free (pwm->filename);
1510 pwm->filename = pwmd_strdup (filename);
1514 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1515 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1516 filename);
1518 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1519 && pwm->pinentry_disabled
1520 && ++pwm->pinentry_try < pwm->pinentry_tries);
1522 pwm->pinentry_try = 0;
1524 if (rc)
1526 pwmd_free (pwm->filename);
1527 pwm->filename = NULL;
1531 pwmd_free (pwm->passphrase_hint);
1532 pwmd_free (pwm->passphrase_info);
1533 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1534 return FINISH (rc);
1537 static gpg_error_t
1538 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1539 void *data, int which)
1541 gpg_error_t rc = 0;
1542 int no_pinentry = 0;
1544 if (!pwm)
1545 return FINISH (GPG_ERR_INV_ARG);
1546 if (!pwm->ctx)
1547 return FINISH (GPG_ERR_INV_STATE);
1549 command_start (pwm);
1550 rc = disable_pinentry (pwm, &no_pinentry);
1551 if (!rc && !no_pinentry)
1552 rc = send_pinentry_options (pwm);
1554 if (!rc)
1556 if (which == PWMD_WHICH_SAVE)
1557 rc = pwmd_command (pwm, NULL, NULL, cb, data, "SAVE %s", args ? args : "");
1558 else if (which == PWMD_WHICH_PASSWD)
1559 rc = pwmd_command (pwm, NULL, NULL, cb, data, "PASSWD %s", args ? args : "");
1560 else if (which == PWMD_WHICH_GENKEY)
1561 rc = pwmd_command (pwm, NULL, NULL, cb, data, "GENKEY %s", args ? args : "");
1564 pwmd_free (pwm->passphrase_hint);
1565 pwmd_free (pwm->passphrase_info);
1566 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1567 return FINISH (rc);
1570 gpg_error_t
1571 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1573 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_PASSWD);
1576 gpg_error_t
1577 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1579 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_SAVE);
1582 gpg_error_t
1583 pwmd_genkey (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1585 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_GENKEY);
1588 static gpg_error_t
1589 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1591 int n, *intp;
1592 size_t *sizetp;
1593 char *arg1, **charpp;
1594 gpg_error_t rc = 0;
1596 if (!pwm)
1597 return GPG_ERR_INV_ARG;
1599 command_start (pwm);
1600 switch (opt)
1602 case PWMD_OPTION_SERVER_VERSION:
1603 if (!get)
1604 return GPG_ERR_NOT_SUPPORTED;
1606 if (!pwm->ctx)
1607 rc = GPG_ERR_INV_STATE;
1608 else
1610 unsigned *u = va_arg (ap, unsigned *);
1611 *u = pwm->version;
1614 break;
1615 case PWMD_OPTION_SIGPIPE:
1616 if (get)
1618 intp = va_arg (ap, int *);
1619 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1620 break;
1623 n = va_arg (ap, int);
1624 if (n < 0 || n > 1)
1626 rc = GPG_ERR_INV_VALUE;
1627 break;
1630 if (n)
1631 pwm->opts |= OPT_SIGPIPE;
1632 else
1633 pwm->opts &= ~OPT_SIGPIPE;
1635 break;
1636 case PWMD_OPTION_LOCK_ON_OPEN:
1637 if (get)
1639 intp = va_arg (ap, int *);
1640 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1641 break;
1644 n = va_arg (ap, int);
1645 if (n < 0 || n > 1)
1647 rc = GPG_ERR_INV_VALUE;
1648 break;
1651 if (n)
1652 pwm->opts |= OPT_LOCK_ON_OPEN;
1653 else
1654 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1656 break;
1657 case PWMD_OPTION_INQUIRE_TOTAL:
1658 if (get)
1660 sizetp = va_arg (ap, size_t *);
1661 *sizetp = pwm->inquire_total;
1662 break;
1665 pwm->inquire_total = va_arg (ap, size_t);
1666 break;
1667 case PWMD_OPTION_STATUS_CB:
1668 if (get)
1670 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1672 *cb = pwm->status_func;
1673 break;
1676 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1677 break;
1678 case PWMD_OPTION_STATUS_DATA:
1679 if (get)
1681 void **data = va_arg (ap, void **);
1683 *data = pwm->status_data;
1684 break;
1687 pwm->status_data = va_arg (ap, void *);
1688 break;
1689 case PWMD_OPTION_NO_PINENTRY:
1690 if (get)
1692 intp = va_arg (ap, int *);
1693 *intp = pwm->disable_pinentry;
1694 break;
1697 n = va_arg (ap, int);
1698 if (n < 0 || n > 1)
1699 rc = GPG_ERR_INV_VALUE;
1700 else
1701 pwm->disable_pinentry = n;
1702 break;
1703 case PWMD_OPTION_LOCAL_PINENTRY:
1704 if (get)
1706 intp = va_arg (ap, int *);
1707 *intp = pwm->local_pinentry;
1708 break;
1711 n = va_arg (ap, int);
1712 if (n < 0 || n > 1)
1713 rc = GPG_ERR_INV_VALUE;
1714 else
1715 pwm->local_pinentry = n;
1717 break;
1718 case PWMD_OPTION_PINENTRY_TIMEOUT:
1719 if (get)
1721 intp = va_arg (ap, int *);
1722 *intp = pwm->pinentry_timeout;
1723 break;
1726 n = va_arg (ap, int);
1727 if (n < 0)
1728 rc = GPG_ERR_INV_VALUE;
1729 else
1730 pwm->pinentry_timeout = n;
1731 break;
1732 case PWMD_OPTION_PINENTRY_TRIES:
1733 if (get)
1735 intp = va_arg (ap, int *);
1736 *intp = pwm->pinentry_tries;
1737 break;
1740 n = va_arg (ap, int);
1741 if (n < 0)
1742 rc = GPG_ERR_INV_VALUE;
1743 else
1744 pwm->pinentry_tries = n;
1745 break;
1746 case PWMD_OPTION_PINENTRY_PATH:
1747 if (get)
1749 charpp = va_arg (ap, char **);
1750 *charpp = pwm->pinentry_path;
1751 break;
1754 arg1 = va_arg (ap, char *);
1755 pwmd_free (pwm->pinentry_path);
1756 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1757 break;
1758 case PWMD_OPTION_PINENTRY_TTY:
1759 if (get)
1761 charpp = va_arg (ap, char **);
1762 *charpp = pwm->pinentry_tty;
1763 break;
1766 arg1 = va_arg (ap, char *);
1767 pwmd_free (pwm->pinentry_tty);
1768 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1769 break;
1770 case PWMD_OPTION_PINENTRY_DISPLAY:
1771 if (get)
1773 charpp = va_arg (ap, char **);
1774 *charpp = pwm->pinentry_display;
1775 break;
1778 arg1 = va_arg (ap, char *);
1779 pwmd_free (pwm->pinentry_display);
1780 pwm->pinentry_display = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
1781 if (!pwm->pinentry_display)
1782 unsetenv ("DISPLAY");
1783 break;
1784 case PWMD_OPTION_PINENTRY_TERM:
1785 if (get)
1787 charpp = va_arg (ap, char **);
1788 *charpp = pwm->pinentry_term;
1789 break;
1792 arg1 = va_arg (ap, char *);
1793 pwmd_free (pwm->pinentry_term);
1794 pwm->pinentry_term = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
1795 if (pwm->pinentry_term)
1796 unsetenv ("TERM");
1797 break;
1798 case PWMD_OPTION_PINENTRY_ERROR:
1799 if (get)
1801 charpp = va_arg (ap, char **);
1802 *charpp = pwm->pinentry_error;
1803 break;
1806 arg1 = va_arg (ap, char *);
1807 pwmd_free (pwm->pinentry_error);
1808 if (pwm->disable_pinentry)
1809 pwm->pinentry_error = arg1 ? pwmd_strdup (arg1) : NULL;
1810 else
1811 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1812 break;
1813 case PWMD_OPTION_PINENTRY_PROMPT:
1814 if (get)
1816 charpp = va_arg (ap, char **);
1817 *charpp = pwm->pinentry_prompt;
1818 break;
1821 arg1 = va_arg (ap, char *);
1822 pwmd_free (pwm->pinentry_prompt);
1823 if (pwm->disable_pinentry)
1824 pwm->pinentry_prompt = arg1 ? pwmd_strdup (arg1) : NULL;
1825 else
1826 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1827 break;
1828 case PWMD_OPTION_PINENTRY_DESC:
1829 if (get)
1831 charpp = va_arg (ap, char **);
1832 *charpp = pwm->pinentry_desc;
1833 break;
1836 arg1 = va_arg (ap, char *);
1837 pwmd_free (pwm->pinentry_desc);
1838 if (pwm->disable_pinentry)
1839 pwm->pinentry_desc = arg1 ? pwmd_strdup (arg1) : NULL;
1840 else
1841 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1842 break;
1843 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1844 if (get)
1846 charpp = va_arg (ap, char **);
1847 *charpp = pwm->pinentry_lcctype;
1848 break;
1851 arg1 = va_arg (ap, char *);
1852 pwmd_free (pwm->pinentry_lcctype);
1853 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1854 break;
1855 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1856 if (get)
1858 charpp = va_arg (ap, char **);
1859 *charpp = pwm->pinentry_lcmessages;
1860 break;
1863 arg1 = va_arg (ap, char *);
1864 pwmd_free (pwm->pinentry_lcmessages);
1865 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1866 break;
1867 case PWMD_OPTION_KNOWNHOST_CB:
1868 if (get)
1870 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
1872 *cb = pwm->kh_cb;
1873 break;
1876 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1877 break;
1878 case PWMD_OPTION_KNOWNHOST_DATA:
1879 if (get)
1881 void **data = va_arg (ap, void **);
1883 *data = pwm->kh_data;
1884 break;
1887 pwm->kh_data = va_arg (ap, void *);
1888 break;
1889 case PWMD_OPTION_SSH_AGENT:
1890 if (get)
1892 intp = va_arg (ap, int *);
1893 *intp = pwm->use_agent;
1894 break;
1897 n = va_arg (ap, int);
1898 if (n < 0 || n > 1)
1899 rc = GPG_ERR_INV_VALUE;
1900 else
1901 pwm->use_agent = n;
1902 break;
1903 case PWMD_OPTION_SSH_PASSPHRASE:
1904 if (get)
1905 return GPG_ERR_NOT_SUPPORTED;
1907 pwmd_free (pwm->ssh_passphrase);
1908 pwm->ssh_passphrase = NULL;
1909 arg1 = va_arg (ap, char *);
1910 if (arg1)
1912 pwm->ssh_passphrase = pwmd_strdup (arg1);
1913 if (!pwm->ssh_passphrase)
1914 return GPG_ERR_ENOMEM;
1916 break;
1917 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE:
1918 if (get)
1920 intp = va_arg (ap, int *);
1921 *intp = pwm->needs_passphrase;
1922 break;
1925 n = va_arg (ap, int);
1926 if (n < 0 || n > 1)
1927 rc = GPG_ERR_INV_VALUE;
1928 else
1929 pwm->needs_passphrase = n;
1930 break;
1931 case PWMD_OPTION_TLS_VERIFY:
1932 if (get)
1934 intp = va_arg (ap, int *);
1935 *intp = pwm->tls_verify;
1936 break;
1939 n = va_arg (ap, int);
1940 if (n < 0 || n > 1)
1941 rc = GPG_ERR_INV_VALUE;
1942 else
1943 pwm->tls_verify = n;
1944 break;
1945 case PWMD_OPTION_TLS_PRIORITY:
1946 if (get)
1948 charpp = va_arg (ap, char **);
1949 *charpp = pwm->tls_priority;
1950 break;
1953 pwmd_free (pwm->tls_priority);
1954 pwm->tls_priority = NULL;
1955 arg1 = va_arg (ap, char *);
1956 if (arg1)
1958 pwm->tls_priority = pwmd_strdup (arg1);
1959 if (!pwm->tls_priority)
1960 rc = GPG_ERR_ENOMEM;
1962 break;
1963 case PWMD_OPTION_SOCKET_TIMEOUT:
1964 if (get)
1966 intp = va_arg (ap, int *);
1967 *intp = pwm->socket_timeout;
1968 break;
1971 n = va_arg (ap, int);
1972 if (n < 0)
1974 rc = GPG_ERR_INV_VALUE;
1975 break;
1977 else
1978 pwm->socket_timeout = n;
1980 #ifdef WITH_SSH
1981 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1983 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1984 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1985 pwm->socket_timeout * 1000);
1987 #endif
1988 #ifdef WITH_GNUTLS
1989 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1990 pwm->tcp->tls->timeout = pwm->socket_timeout;
1991 #endif
1992 break;
1993 case PWMD_OPTION_OVERRIDE_INQUIRE:
1994 if (get)
1996 intp = va_arg (ap, int *);
1997 *intp = pwm->override_inquire;
1998 break;
2001 n = va_arg (ap, int);
2002 if (n < 0 || n > 1)
2003 rc = GPG_ERR_INV_VALUE;
2004 else
2005 pwm->override_inquire = n;
2006 break;
2007 default:
2008 rc = GPG_ERR_UNKNOWN_OPTION;
2009 break;
2012 return FINISH (rc);
2015 gpg_error_t
2016 pwmd_setopt (pwm_t * pwm, int opt, ...)
2018 va_list ap;
2019 gpg_error_t rc = 0;
2021 va_start (ap, opt);
2022 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
2023 va_end (ap);
2024 return FINISH (rc);
2027 gpg_error_t
2028 pwmd_getopt (pwm_t *pwm, int opt, ...)
2030 va_list ap;
2031 gpg_error_t rc = 0;
2033 va_start (ap, opt);
2034 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
2035 va_end (ap);
2036 return FINISH (rc);
2039 gpg_error_t
2040 set_rcdefaults (pwm_t *pwm, char *filename)
2042 char *f;
2043 FILE *fp;
2044 char *line = NULL, *p;
2045 unsigned line_n = 0;
2046 gpg_error_t rc = 0;
2048 if (!filename && isatty (STDIN_FILENO))
2050 char buf[256];
2051 int err = ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
2053 if (!err)
2055 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, buf);
2056 if (rc)
2057 return rc;
2059 if (getenv ("TERM"))
2061 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, getenv ("TERM"));
2062 if (rc)
2063 return rc;
2068 if (!filename && getenv ("DISPLAY"))
2070 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, getenv ("DISPLAY"));
2071 if (rc)
2072 return rc;
2075 f = _expand_homedir (filename ? filename : (char *)"~/.config/libpwmd.conf",
2076 NULL);
2077 if (f)
2079 line = pwmd_malloc (LINE_MAX);
2080 if (line)
2082 fp = fopen (f, "r");
2083 if (!fp)
2085 pwmd_free (line);
2086 pwmd_free (f);
2087 return 0;
2090 else
2091 rc = GPG_ERR_ENOMEM;
2093 else
2094 rc = GPG_ERR_ENOMEM;
2096 if (rc)
2098 pwmd_free (f);
2099 pwmd_free (line);
2100 return rc;
2103 while ((p = fgets (line, LINE_MAX, fp)))
2105 char name[32] = {0}, val[512] = {0};
2106 char *np;
2107 char *t;
2108 size_t len = 0;
2110 line_n++;
2112 while (isspace (*p))
2113 p++;
2115 if (!*p || *p == '#')
2116 continue;
2118 if (p[strlen (p)-1] == '\n')
2119 p[strlen (p)-1] = 0;
2121 t = strchr (p, '=');
2122 if (!t)
2124 fprintf(stderr, N_("%s(%u): malformed line\n"), f, line_n);
2125 continue;
2128 for (np = name; p != t; p++)
2130 if (++len == sizeof (name))
2131 break;
2133 if (isspace (*p))
2134 break;
2136 *np++ = *p;
2139 while (isspace (*t))
2140 t++;
2141 t++; // '='
2142 while (isspace (*t))
2143 t++;
2145 strncpy (val, t, sizeof (val)-1);
2147 if (!strcasecmp (name, "pinentry-path"))
2148 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, val);
2149 else if (!strcasecmp (name, "pinentry-tries"))
2150 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, atoi (val));
2151 else if (!strcasecmp (name, "pinentry-timeout"))
2152 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, atoi (val));
2153 else if (!strcasecmp (name, "no-pinentry"))
2154 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, !!(atoi (val)));
2155 else if (!strcasecmp (name, "local-pinentry"))
2156 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, !!(atoi (val)));
2157 else if (!strcasecmp (name, "pinentry-display"))
2158 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, val);
2159 else if (!strcasecmp (name, "pinentry-ttyname"))
2160 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, val);
2161 else if (!strcasecmp (name, "pinentry-ttytype"))
2162 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, val);
2163 else if (!strcasecmp (name, "pinentry-lc-messages"))
2164 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, val);
2165 else if (!strcasecmp (name, "pinentry-lc-ctype"))
2166 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, val);
2167 else if (!strcasecmp (name, "no-ssh-agent"))
2168 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, !(atoi (val)));
2169 else if (!strcasecmp (name, "no-tls-verify"))
2170 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, !(atoi (val)));
2171 else if (!strcasecmp (name, "tls-priority"))
2172 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, val);
2173 else if (!strcasecmp (name, "socket-timeout"))
2174 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, atoi (val));
2175 else if (!strcasecmp (name, "no-lock"))
2176 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, !(atoi (val)));
2177 else if (!strcasecmp (name, "include"))
2178 rc = set_rcdefaults (pwm, val);
2179 else
2180 fprintf(stderr, N_("%s(%u): invalid option '%s', ignored.\n"), f,
2181 line_n, name);
2183 if (rc)
2184 break;
2187 fclose (fp);
2188 pwmd_free (line);
2189 pwmd_free (f);
2190 return rc;
2193 gpg_error_t
2194 pwmd_new (const char *name, pwm_t ** pwm)
2196 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
2197 gpg_error_t rc;
2199 if (!h)
2200 return FINISH (GPG_ERR_ENOMEM);
2202 if (name)
2204 h->name = pwmd_strdup (name);
2205 if (!h->name)
2207 pwmd_free (h);
2208 return FINISH (GPG_ERR_ENOMEM);
2212 reset_handle (h);
2213 h->pinentry_timeout = -1;
2214 h->current_pinentry_timeout = -1;
2215 h->pinentry_tries = 3;
2216 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2217 h->prot = PWMD_IP_ANY;
2218 h->socket_timeout = 120;
2219 h->tls_verify = 1;
2220 #endif
2221 h->opts |= OPT_LOCK_ON_OPEN;
2223 rc = set_rcdefaults (h, NULL);
2224 if (rc)
2225 goto fail;
2227 *pwm = h;
2228 return 0;
2230 fail:
2231 pwmd_close (h);
2232 return FINISH (rc);
2235 void
2236 pwmd_free (void *ptr)
2238 _xfree (ptr);
2241 void *
2242 pwmd_malloc (size_t size)
2244 return _xmalloc (size);
2247 void *
2248 pwmd_calloc (size_t nmemb, size_t size)
2250 return _xcalloc (nmemb, size);
2253 void *
2254 pwmd_realloc (void *ptr, size_t size)
2256 return _xrealloc (ptr, size);
2259 char *
2260 pwmd_strdup (const char *str)
2262 char *t;
2263 size_t len;
2264 register size_t c;
2266 len = strlen (str);
2267 t = _xmalloc ((len + 1) * sizeof (char));
2268 if (!t)
2269 return NULL;
2271 for (c = 0; c < len; c++)
2272 t[c] = str[c];
2274 t[c] = 0;
2275 return t;
2278 char *
2279 pwmd_strdup_printf (const char *fmt, ...)
2281 va_list ap, ap2;
2282 int len;
2283 char *buf;
2285 if (!fmt)
2286 return NULL;
2288 va_start (ap, fmt);
2289 va_copy (ap2, ap);
2290 len = vsnprintf (NULL, 0, fmt, ap);
2291 va_end (ap);
2292 buf = pwmd_malloc (++len);
2293 if (buf)
2294 vsnprintf (buf, len, fmt, ap2);
2296 va_end (ap2);
2297 return buf;
2300 gpg_error_t
2301 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
2302 size_t * len, pwmd_pinentry_t which)
2304 #ifndef WITH_PINENTRY
2305 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
2306 #else
2307 gpg_error_t rc;
2309 command_start (pwm);
2310 if (which == PWMD_PINENTRY_CONFIRM && pwm->disable_pinentry)
2312 rc = get_password (pwm, NULL, NULL, which, 1);
2313 return FINISH (rc);
2316 rc = _pwmd_getpin (pwm, filename, result, len, which);
2317 return FINISH (rc);
2318 #endif
2321 const char *
2322 pwmd_version ()
2324 return LIBPWMD_VERSION_STR;
2327 unsigned int
2328 pwmd_features ()
2330 unsigned int n = 0;
2332 #ifdef WITH_PINENTRY
2333 n |= PWMD_FEATURE_PINENTRY;
2334 #endif
2335 #ifdef WITH_SSH
2336 n |= PWMD_FEATURE_SSH;
2337 #endif
2338 #ifdef WITH_QUALITY
2339 n |= PWMD_FEATURE_QUALITY;
2340 #endif
2341 #ifdef WITH_GNUTLS
2342 n |= PWMD_FEATURE_GNUTLS;
2343 #endif
2344 return n;
2347 gpg_error_t
2348 pwmd_fd (pwm_t * pwm, int *fd)
2350 if (!pwm || !fd)
2351 return FINISH (GPG_ERR_INV_ARG);
2353 if (pwm->fd == -1)
2354 return FINISH (GPG_ERR_INV_STATE);
2356 *fd = pwm->fd;
2357 return 0;
2360 void
2361 pwmd_set_pointer (pwm_t *pwm, void *data)
2363 pwm->user_data = data;
2366 void *
2367 pwmd_get_pointer (pwm_t *pwm)
2369 return pwm->user_data;
2373 pwmd_gnutls_error (pwm_t *pwm, const char **str)
2375 #ifndef WITH_GNUTLS
2376 (void)pwm;
2377 (void)str;
2378 return 0;
2379 #else
2380 if (str && pwm && pwm->tls_error)
2381 *str = gnutls_strerror (pwm->tls_error);
2383 return pwm ? pwm->tls_error : 0;
2384 #endif
2387 gpg_error_t
2388 pwmd_cancel (pwm_t *pwm)
2390 if (!pwm)
2391 return FINISH (GPG_ERR_INV_ARG);
2393 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2394 if (pwm->fd == -1 && !pwm->tcp)
2395 #else
2396 if (pwm->fd == -1)
2397 #endif
2398 return FINISH (GPG_ERR_INV_STATE);
2400 /* Can only cancel the connection for the time being. */
2401 if (pwm->connected)
2402 return FINISH (GPG_ERR_INV_STATE);
2404 pwm->cancel = 1;
2405 return 0;
2408 gpg_error_t
2409 pwmd_test_quality (const char *str, double *result)
2411 #ifndef WITH_QUALITY
2412 (void)str;
2413 (void)result;
2414 return GPG_ERR_NOT_IMPLEMENTED;
2415 #else
2416 if (!result)
2417 return GPG_ERR_INV_ARG;
2419 *result = ZxcvbnMatch (str, NULL, NULL);
2420 return 0;
2421 #endif