Add pwmd_connect_fd() and read/write callbacks.
[libpwmd.git] / src / libpwmd.c
blob17fb47fb764aa195810475d19aef1dea1dc56695
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 pwm_t *pwm = assuan_get_pointer (ctx);
97 if (pwm->read_cb)
98 return pwm->read_cb (pwm->read_cb_data, fd, data, len);
100 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
101 #ifdef WITH_SSH
102 if (pwm && pwm->tcp && pwm->tcp->ssh)
103 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
104 #endif
105 #ifdef WITH_GNUTLS
106 if (pwm && pwm->tcp && pwm->tcp->tls)
107 return tls_read_hook (pwm, fd, data, len);
108 #endif
109 #endif
111 return read ((int) fd, data, len);
114 ssize_t
115 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
116 size_t len)
118 pwm_t *pwm = assuan_get_pointer (ctx);
119 ssize_t wrote;
121 if (pwm->write_cb)
122 return pwm->write_cb (pwm->write_cb_data, fd, data, len);
124 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
125 #ifdef WITH_SSH
126 if (pwm && pwm->tcp && pwm->tcp->ssh)
127 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
128 #endif
129 #ifdef WITH_GNUTLS
130 if (pwm && pwm->tcp && pwm->tcp->tls)
131 return tls_write_hook (pwm, fd, data, len);
132 #endif
133 #endif
135 /* libassuan cannot handle EAGAIN when doing writes. */
138 wrote = write ((int) fd, data, len);
139 if (wrote == -1 && errno == EAGAIN)
140 usleep (50000);
142 while (wrote == -1 && errno == EAGAIN);
144 return wrote;
147 pid_t
148 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
149 int options)
151 (void)ctx;
152 (void)action;
153 return waitpid (pid, status, options);
156 gpg_error_t
157 pwmd_init ()
159 static int initialized;
161 #ifdef WITH_GNUTLS
162 // May be called more than once.
163 gnutls_global_init ();
164 #endif
166 if (initialized)
167 return 0;
169 #ifdef ENABLE_NLS
170 bindtextdomain ("libpwmd", LOCALEDIR);
171 #endif
172 #ifdef WITH_SSH
173 libssh2_init (0);
174 #endif
175 gpgrt_init ();
176 //gpgrt_set_alloc_func (_xrealloc_gpgrt);
178 #ifdef WITH_QUALITY
179 ZxcvbnInit (NULL);
180 #endif
182 initialized = 1;
183 return 0;
186 void
187 pwmd_deinit ()
189 #ifdef WITH_GNUTLS
190 gnutls_global_deinit ();
191 #endif
192 #ifdef WITH_QUALITY
193 ZxcvbnUnInit();
194 #endif
197 gpg_error_t
198 _connect_finalize (pwm_t * pwm)
200 gpg_error_t rc = 0;
201 char *result = NULL;
202 int active[2];
203 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
205 if (n <= 0)
206 return GPG_ERR_EBADFD;
208 pwm->fd = active[0];
209 #ifdef WITH_PINENTRY
210 pwm->pinentry_pid = -1;
211 #endif
213 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "GETINFO VERSION");
214 if (!rc)
216 pwm->version = strtoul (result, NULL, 16);
217 pwmd_free (result);
220 if (!rc && pwm->name)
221 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
222 pwm->name);
224 return rc;
227 static gpg_error_t
228 connect_uds (pwm_t * pwm, const char *path)
230 char *socketpath = NULL;
231 struct passwd pw;
232 char *pwbuf;
233 gpg_error_t rc;
235 if (!pwm)
236 return GPG_ERR_INV_ARG;
238 pwbuf = _getpwuid (&pw);
239 if (!pwbuf)
240 return gpg_error_from_syserror ();
242 if (!path || !*path)
243 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
244 else
245 socketpath = _expand_homedir ((char *) path, &pw);
247 pwmd_free (pwbuf);
248 if (!socketpath)
249 return GPG_ERR_ENOMEM;
251 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
252 pwmd_free (socketpath);
253 return rc ? rc : _connect_finalize (pwm);
256 static gpg_error_t
257 init_handle (pwm_t * pwm)
259 gpg_error_t rc;
260 static struct assuan_malloc_hooks mhooks = {
261 pwmd_malloc, pwmd_realloc, pwmd_free
263 static struct assuan_system_hooks shooks = {
264 ASSUAN_SYSTEM_HOOKS_VERSION,
265 __assuan_usleep,
266 __assuan_pipe,
267 __assuan_close,
268 hook_read,
269 hook_write,
270 //FIXME
271 NULL, //recvmsg
272 NULL, //sendmsg both are used for FD passing
273 __assuan_spawn,
274 hook_waitpid,
275 __assuan_socketpair,
276 __assuan_socket,
277 __assuan_connect
280 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
281 NULL);
282 if (rc)
283 return rc;
285 assuan_set_pointer (pwm->ctx, pwm);
286 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
287 return 0;
290 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
291 void
292 free_tcp (pwm_t *pwm)
294 struct tcp_s *tcp = pwm->tcp;
296 if (!tcp)
297 return;
299 #ifdef WITH_SSH
300 _free_ssh_conn (tcp->ssh);
301 #endif
302 #ifdef WITH_GNUTLS
303 tls_free (pwm);
304 #endif
306 pwmd_free (tcp->host);
307 if (tcp->addrs)
309 freeaddrinfo (tcp->addrs);
310 tcp->addrs = NULL;
313 pthread_cond_destroy (&tcp->dns_cond);
314 pthread_mutex_destroy (&tcp->dns_mutex);
315 pwmd_free (tcp);
316 pwm->tcp = NULL;
318 #endif
320 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
321 static void *
322 resolve_host_thread (void *arg)
324 pwm_t *pwm = arg;
325 struct addrinfo hints = { 0 };
326 char portstr[6];
328 switch (pwm->prot)
330 case PWMD_IP_ANY:
331 hints.ai_family = AF_UNSPEC;
332 break;
333 case PWMD_IPV4:
334 hints.ai_family = AF_INET;
335 break;
336 case PWMD_IPV6:
337 hints.ai_family = AF_INET6;
338 break;
341 hints.ai_socktype = SOCK_STREAM;
342 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
343 int *n = pwmd_malloc (sizeof (int));
344 pthread_cleanup_push (pwmd_free, n);
345 *n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
346 pthread_cleanup_pop (0);
347 pthread_cond_broadcast (&pwm->tcp->dns_cond);
348 pthread_exit (n);
349 return NULL;
352 gpg_error_t
353 tcp_connect_common (pwm_t * pwm)
355 #define TS_TIMEOUT 50000000L
356 int n;
357 gpg_error_t rc = 0;
358 pthread_t tid;
359 time_t now;
361 time (&now);
362 n = pthread_create (&tid, NULL, resolve_host_thread, pwm);
363 if (n)
364 return gpg_error_from_errno (n);
366 pthread_mutex_lock (&pwm->tcp->dns_mutex);
368 for (;;)
370 struct timespec ts;
371 int *result = NULL;
373 clock_gettime (CLOCK_REALTIME, &ts);
374 if (ts.tv_nsec + TS_TIMEOUT >= 1000000000LL) {
375 ts.tv_sec++;
376 ts.tv_nsec = 0;
378 else
379 ts.tv_nsec += TS_TIMEOUT;
381 if (pwm->cancel)
383 #ifdef HAVE_PTHREAD_CANCEL
384 pthread_cancel (tid);
385 pthread_join (tid, NULL);
386 #else
387 pthread_join (tid, (void **)&result);
388 pwmd_free (result);
389 #endif
390 return GPG_ERR_CANCELED;
393 n = pthread_cond_timedwait (&pwm->tcp->dns_cond, &pwm->tcp->dns_mutex,
394 &ts);
395 if (n == ETIMEDOUT)
397 if (pwm->socket_timeout && ts.tv_sec - now >= pwm->socket_timeout)
399 #ifdef HAVE_PTHREAD_CANCEL
400 pthread_cancel (tid);
401 pthread_join (tid, NULL);
402 #else
403 pthread_join (tid, (void **)&result);
404 pwmd_free (result);
405 #endif
406 return GPG_ERR_ETIMEDOUT;
409 continue;
411 else if (n)
413 #ifdef HAVE_PTHREAD_CANCEL
414 pthread_cancel (tid);
415 pthread_join (tid, NULL);
416 #else
417 pthread_join (tid, (void **)&result);
418 pwmd_free (result);
419 #endif
420 return gpg_error_from_errno (n);
423 pthread_join (tid, (void **)&result);
424 n = *result;
425 pwmd_free (result);
426 break;
429 if (n)
430 return GPG_ERR_UNKNOWN_HOST; //FIXME
432 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
433 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
435 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
436 if (pwm->fd == -1)
438 rc = gpg_error_from_syserror ();
439 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
440 break;
441 continue;
444 if (fcntl (pwm->fd, F_SETFL, O_NONBLOCK) == -1)
446 rc = gpg_error_from_syserror ();
447 break;
450 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
451 pwm->tcp->addr->ai_family == AF_INET6
452 ? sizeof (struct sockaddr_in6)
453 : sizeof (struct sockaddr)) == -1)
455 struct timeval tv;
456 fd_set wfds;
457 unsigned elapsed = 0;
459 rc = gpg_error_from_syserror ();
460 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
462 close (pwm->fd);
463 pwm->fd = -1;
464 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
465 return rc;
466 continue;
469 again:
470 tv.tv_sec = 1;
471 tv.tv_usec = 0;
472 FD_ZERO (&wfds);
473 FD_SET (pwm->fd, &wfds);
474 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
475 rc = 0;
476 if (!n || pwm->cancel)
478 if (pwm->cancel)
479 rc = gpg_error (GPG_ERR_CANCELED);
480 else if (++elapsed >= pwm->socket_timeout)
481 rc = gpg_error (GPG_ERR_ETIMEDOUT);
482 else
483 goto again;
485 else if (n != -1)
487 socklen_t len = sizeof(int);
489 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
490 if (n)
491 rc = gpg_error_from_errno (n);
493 else if (n == -1)
494 rc = gpg_error_from_syserror ();
496 if (rc)
498 close (pwm->fd);
499 pwm->fd = -1;
500 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
501 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
502 || pwm->cancel)
503 return rc;
505 else
506 break;
508 else
509 break;
512 if (!rc)
513 if (fcntl (pwm->fd, F_SETFL, 0) == -1)
514 rc = gpg_error_from_syserror ();
516 return rc;
518 #endif
520 static void
521 command_start (pwm_t *pwm)
523 pwm->cancel = 0;
526 gpg_error_t
527 pwmd_connect_fd (pwm_t * pwm, int fd)
529 gpg_error_t rc = 0;
531 if (!pwm)
532 return FINISH (GPG_ERR_INV_ARG);
533 else if (!pwm->ctx)
535 rc = init_handle (pwm);
536 if (rc)
537 return FINISH (rc);
540 command_start (pwm);
542 if (!(pwm->opts & OPT_SIGPIPE))
543 signal (SIGPIPE, SIG_IGN);
545 rc = assuan_socket_connect_fd (pwm->ctx, fd, 0);
546 if (!rc)
548 pwm->fd = fd;
549 pwm->connected = pwm->user_fd = 1;
550 rc = _connect_finalize (pwm);
553 if (rc)
554 pwmd_disconnect (pwm);
556 return FINISH (rc);
559 gpg_error_t
560 pwmd_connect (pwm_t * pwm, const char *url, ...)
562 const char *p = url;
563 gpg_error_t rc;
565 if (!pwm)
566 return FINISH (GPG_ERR_INV_ARG);
567 else if (!pwm->ctx)
569 rc = init_handle (pwm);
570 if (rc)
571 return FINISH (GPG_ERR_INV_ARG);
574 command_start (pwm);
576 if (!(pwm->opts & OPT_SIGPIPE))
577 signal (SIGPIPE, SIG_IGN);
579 #ifdef WITH_GNUTLS
580 pwm->tls_error = 0;
581 #endif
582 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
584 if (p && (*p == '/' || *p == '~'))
585 rc = connect_uds (pwm, p);
586 else if (!p || !strncmp (p, "file://", 7))
588 if (p)
589 p += 7;
590 #ifdef DEFAULT_PWMD_SOCKET
591 else
592 p = DEFAULT_PWMD_SOCKET;
593 #endif
594 rc = connect_uds (pwm, p);
596 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
597 !strncmp (p, "ssh4://", 7))
599 #ifndef WITH_SSH
600 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
601 #else
602 char *host = NULL;
603 int port;
604 char *username = NULL;
606 if (!strncmp (p, "ssh6://", 7))
608 pwm->prot = PWMD_IPV6;
609 p += 7;
611 else if (!strncmp (p, "ssh4://", 7))
613 pwm->prot = PWMD_IPV4;
614 p += 7;
616 else
618 pwm->prot = PWMD_IP_ANY;
619 p += 6;
622 rc = _parse_ssh_url (p, &host, &port, &username);
623 if (!rc)
625 va_list ap;
626 char *identity = NULL;
627 char *knownhosts = NULL;
629 va_start (ap, url);
630 identity = va_arg (ap, char *);
632 if (!identity && !pwm->use_agent)
633 rc = GPG_ERR_INV_ARG;
634 else
635 knownhosts = va_arg (ap, char *);
637 va_end (ap);
639 if (!rc)
640 rc = _do_ssh_connect (pwm, host, port, identity, username,
641 knownhosts);
642 if (!rc)
644 rc = _connect_finalize (pwm);
645 if (rc)
646 free_tcp (pwm);
650 pwmd_free (host);
651 pwmd_free (username);
652 pwm->local_pinentry = 1;
653 pwmd_free (pwm->ssh_passphrase);
654 pwm->ssh_passphrase = NULL;
655 #endif
657 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
658 !strncmp (p, "tls4://", 7))
660 #ifndef WITH_GNUTLS
661 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
662 #else
663 char *host = NULL;
664 int port;
666 if (!strncmp (p, "tls6://", 7))
668 pwm->prot = PWMD_IPV6;
669 p += 7;
671 else if (!strncmp (p, "tls4://", 7))
673 pwm->prot = PWMD_IPV4;
674 p += 7;
676 else
678 pwm->prot = PWMD_IP_ANY;
679 p += 6;
682 rc = tls_parse_url (p, &host, &port);
683 if (!rc)
685 va_list ap;
686 char *clientcert = NULL;
687 char *clientkey = NULL;
688 char *cacert = NULL;
689 char *server_fp = NULL;
691 va_start (ap, url);
692 clientcert = va_arg (ap, char *);
694 if (!clientcert)
695 rc = GPG_ERR_INV_ARG;
696 else
698 clientkey = va_arg (ap, char *);
699 if (!clientkey)
700 rc = GPG_ERR_INV_ARG;
701 else
703 cacert = va_arg (ap, char *);
704 if (!cacert)
705 rc = GPG_ERR_INV_ARG;
706 else
707 server_fp = va_arg (ap, char *);
711 va_end (ap);
713 if (!rc)
714 rc = tls_connect (pwm, host, port, clientcert, clientkey, cacert,
715 pwm->tls_priority, server_fp, pwm->tls_verify);
716 if (!rc)
718 rc = _connect_finalize (pwm);
719 if (rc)
720 free_tcp (pwm);
724 pwmd_free (host);
725 pwm->local_pinentry = 1;
726 #endif
729 if (!rc)
730 pwm->connected = 1;
732 return FINISH (rc);
735 static void
736 disconnect (pwm_t * pwm)
738 if (!pwm)
739 return;
741 if (pwm->ctx)
742 assuan_release (pwm->ctx);
744 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
745 free_tcp (pwm);
746 #endif
747 pwm->ctx = NULL;
748 pwm->fd = -1;
749 pwm->connected = pwm->user_fd = 0;
752 void
753 pwmd_close (pwm_t * pwm)
755 if (!pwm)
756 return;
758 disconnect (pwm);
759 pwmd_free (pwm->pinentry_error);
760 pwmd_free (pwm->pinentry_desc);
761 pwmd_free (pwm->pinentry_prompt);
762 pwmd_free (pwm->pinentry_tty);
763 pwmd_free (pwm->pinentry_display);
764 pwmd_free (pwm->pinentry_term);
765 pwmd_free (pwm->pinentry_lcctype);
766 pwmd_free (pwm->pinentry_lcmessages);
767 pwmd_free (pwm->filename);
768 pwmd_free (pwm->name);
769 pwmd_free (pwm->passphrase_info);
770 pwmd_free (pwm->passphrase_hint);
771 pwmd_free (pwm->ssh_passphrase);
772 pwmd_free (pwm->tls_priority);
774 #ifdef WITH_PINENTRY
775 if (pwm->pctx)
776 _pinentry_disconnect (pwm);
777 #endif
779 pwmd_free (pwm);
782 static gpg_error_t
783 inquire_realloc_cb (void *data, const void *buffer, size_t len)
785 membuf_t *mem = (membuf_t *) data;
786 void *p;
788 if (!buffer)
789 return 0;
791 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
792 return gpg_error (GPG_ERR_ENOMEM);
794 mem->buf = p;
795 memcpy ((char *) mem->buf + mem->len, buffer, len);
796 mem->len += len;
797 return 0;
800 static gpg_error_t
801 get_password (pwm_t * pwm, char **result, size_t * len,
802 pwmd_pinentry_t w, int echo)
804 char buf[ASSUAN_LINELENGTH+1] = { 0 }, *p;
805 struct termios told, tnew;
806 char *key = NULL;
808 if (result)
809 *result = NULL;
811 if (len)
812 *len = 0;
814 if (!isatty (STDIN_FILENO))
816 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
817 return GPG_ERR_ENOTTY;
820 if (!echo)
822 if (tcgetattr (STDIN_FILENO, &told) == -1)
823 return gpg_error_from_syserror ();
825 memcpy (&tnew, &told, sizeof (struct termios));
826 tnew.c_lflag &= ~(ECHO);
827 tnew.c_lflag |= ICANON | ECHONL;
829 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
831 int n = errno;
833 tcsetattr (STDIN_FILENO, TCSANOW, &told);
834 return gpg_error_from_errno (n);
838 if (pwm->passphrase_hint)
839 fprintf(stderr, N_("Key info: %s\n"), pwm->passphrase_hint);
841 switch (w)
843 case PWMD_PINENTRY_OPEN:
844 fprintf (stderr, N_("Passphrase for %s: "), pwm->filename);
845 break;
846 case PWMD_PINENTRY_OPEN_FAILED:
847 fprintf (stderr, N_("Invalid passphrase. Passphrase for %s: "),
848 pwm->filename);
849 break;
850 case PWMD_PINENTRY_SAVE:
851 fprintf (stderr, N_("New passphrase for %s: "), pwm->filename);
852 break;
853 case PWMD_PINENTRY_SAVE_CONFIRM:
854 fprintf (stderr, N_("Repeat passphrase: "));
855 break;
856 case PWMD_PINENTRY_CONFIRM:
857 if (pwm->pinentry_desc)
858 fprintf (stderr, "%s", pwm->pinentry_desc);
860 if (pwm->pinentry_prompt)
861 fprintf (stderr, "%s", pwm->pinentry_prompt);
862 else
863 fprintf(stderr, N_("Confirm [y/N]:"));
864 default:
865 break;
868 p = fgets (buf, sizeof (buf), stdin);
870 if (!echo)
871 tcsetattr (STDIN_FILENO, TCSANOW, &told);
873 if (!p || feof (stdin))
875 clearerr (stdin);
876 return GPG_ERR_CANCELED;
879 /* Strip the newline character. */
880 p[strlen (p) - 1] = 0;
882 if (buf[0])
884 if (w == PWMD_PINENTRY_CONFIRM)
886 if (*p != 'y' && *p != 'Y')
887 return GPG_ERR_CANCELED;
888 return 0;
891 key = pwmd_strdup_printf ("%s", p);
892 wipememory (buf, 0, sizeof (buf));
893 if (!key)
894 return GPG_ERR_ENOMEM;
896 if (result)
897 *result = key;
899 if (len)
900 *len = strlen (key);
902 else
904 if (w == PWMD_PINENTRY_CONFIRM)
905 return GPG_ERR_CANCELED;
907 /* To satisfy inquire_cb(). */
908 if (result)
909 *result = pwmd_strdup ("");
911 if (len)
912 *len = 1;
915 return 0;
918 gpg_error_t
919 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
921 gpg_error_t rc;
922 int new_password = 0;
923 char *password = NULL, *newpass = NULL;
924 int error = 0;
926 command_start (pwm);
928 if (data)
929 *data = NULL;
931 if (size)
932 *size = 0;
934 if (!strcmp (keyword, "NEW_PASSPHRASE"))
935 new_password = 1;
937 if (!new_password && pwm->pinentry_try)
938 error = 1;
940 again:
941 if (pwm->disable_pinentry)
943 rc = get_password (pwm, &password, size,
944 new_password ? PWMD_PINENTRY_SAVE :
945 error ? PWMD_PINENTRY_OPEN_FAILED :
946 PWMD_PINENTRY_OPEN, 0);
947 if (!rc && new_password)
948 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
951 else
953 pwmd_pinentry_t which;
955 if (error)
956 which = new_password
957 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
958 else
959 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
961 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
962 if (!rc && new_password)
963 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
964 PWMD_PINENTRY_SAVE_CONFIRM);
967 if (!rc && new_password)
969 if ((!password && newpass) || (!newpass && password)
970 || (newpass && password && strcmp (newpass, password)))
972 if (pwm->disable_pinentry)
973 fprintf (stderr, N_("Passphrases do not match.\n"));
975 pwmd_free (password);
976 pwmd_free (newpass);
977 password = newpass = NULL;
978 error = 1;
979 goto again;
983 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
984 pwmd_free (newpass);
985 if (!rc && data)
986 *data = password;
987 else
988 pwmd_free (password);
990 return rc;
993 static gpg_error_t
994 inquire_cb (void *data, const char *keyword)
996 pwm_t *pwm = (pwm_t *) data;
997 gpg_error_t rc = 0;
998 int free_result = 0;
999 char *result = NULL;
1000 int is_password = 0;
1001 int new_password = 0;
1003 if (!strcmp (keyword, "PASSPHRASE") || !strcmp (keyword, "SIGN_PASSPHRASE"))
1004 is_password = 1;
1005 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
1006 new_password = 1;
1008 /* Shouldn't get this far without a callback. */
1009 if (!pwm->override_inquire && !pwm->inquire_func
1010 && !is_password && !new_password)
1011 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
1013 for (;;)
1015 size_t len = 0;
1016 gpg_error_t arc;
1018 result = NULL;
1020 if (!pwm->override_inquire && (is_password || new_password))
1022 free_result = 1;
1023 rc = pwmd_password (data, keyword, &result, &len);
1024 if (!rc)
1025 rc = GPG_ERR_EOF;
1027 else
1028 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
1029 &len);
1031 /* gpg will truncate a passphrase at the first nil byte which may be bad
1032 * for generated key files. */
1033 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
1034 && (is_password || new_password))
1036 if (len && result && *result)
1038 for (size_t n = 0; n < len; n++)
1040 if (result[n] == 0 && n+1 != len)
1041 rc = GPG_ERR_INV_PASSPHRASE;
1046 cancel:
1047 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
1049 #ifndef LIBASSUAN_2_1_0
1050 gpg_error_t trc = rc;
1052 /* Cancel this inquire. */
1053 rc = assuan_send_data (pwm->ctx, NULL, 1);
1054 if (!rc)
1056 char *line;
1057 size_t len;
1059 /* There is a bug (or feature?) in assuan_send_data() that
1060 * when cancelling an inquire the next read from the server is
1061 * not done until the next command making the next command
1062 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
1064 rc = assuan_read_line (pwm->ctx, &line, &len);
1066 /* Restore the original error. This differs from the error
1067 * returned from the pwmd command (GPG_ERR_CANCELED). This
1068 * error is returned to the calling function.
1070 if (!rc)
1071 rc = trc;
1073 #endif
1074 break;
1077 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
1079 if (len <= 0 && !result)
1081 rc = 0;
1082 break;
1084 else if ((len <= 0 && result) || (len && !result))
1086 rc = gpg_error (GPG_ERR_INV_ARG);
1087 break;
1090 if (pwm->inquire_maxlen
1091 && pwm->inquire_sent + len > pwm->inquire_maxlen)
1093 rc = gpg_error (GPG_ERR_TOO_LARGE);
1094 if (!free_result)
1095 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
1096 &result, &len);
1097 goto cancel;
1100 arc = assuan_send_data (pwm->ctx, result, len);
1101 if (gpg_err_code (rc) == GPG_ERR_EOF)
1103 rc = arc;
1104 break;
1107 rc = arc;
1109 else if (rc)
1110 break;
1112 if (!rc)
1114 pwm->inquire_sent += len;
1116 if (pwm->status_func)
1118 char buf[ASSUAN_LINELENGTH];
1120 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
1121 pwm->inquire_total);
1122 rc = pwm->status_func (pwm->status_data, buf);
1123 if (rc)
1124 continue;
1129 if (free_result)
1130 pwmd_free (result);
1132 pwm->inquire_maxlen = pwm->inquire_sent = 0;
1133 return rc;
1136 static gpg_error_t
1137 parse_assuan_line (pwm_t * pwm)
1139 gpg_error_t rc;
1140 char *line;
1141 size_t len;
1143 rc = assuan_read_line (pwm->ctx, &line, &len);
1144 if (!rc)
1146 if (line[0] == 'O' && line[1] == 'K' &&
1147 (line[2] == 0 || line[2] == ' '))
1150 else if (line[0] == '#')
1153 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
1155 rc = status_cb (pwm, line[1] == 0 ? line + 1 : line + 2);
1157 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
1158 (line[3] == 0 || line[3] == ' '))
1160 line += 4;
1161 rc = strtol (line, NULL, 10);
1165 return rc;
1168 static void
1169 reset_handle (pwm_t *pwm)
1171 pwm->fd = -1;
1172 pwm->user_fd = 0;
1173 pwm->cancel = 0;
1174 pwm->pinentry_disabled = 0;
1175 #ifdef WITH_PINENTRY
1176 if (pwm->pctx)
1177 _pinentry_disconnect (pwm);
1178 #endif
1179 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1180 #ifdef WITH_GNUTLS
1181 pwm->tls_error = 0;
1182 #endif
1184 if (pwm->tcp)
1185 pwm->tcp->rc = 0;
1186 #endif
1189 gpg_error_t
1190 pwmd_disconnect (pwm_t * pwm)
1192 if (!pwm)
1193 return FINISH (GPG_ERR_INV_ARG);
1195 command_start (pwm);
1197 if (pwm->fd == -1)
1198 return FINISH (GPG_ERR_INV_STATE);
1200 disconnect (pwm);
1201 reset_handle (pwm);
1202 return 0;
1205 /* Note that this should only be called when not in a command. */
1206 gpg_error_t
1207 pwmd_process (pwm_t * pwm)
1209 gpg_error_t rc = 0;
1210 fd_set fds;
1211 struct timeval tv = { 0, 0 };
1212 int n;
1214 if (!pwm || pwm->fd == -1)
1215 return FINISH (GPG_ERR_INV_ARG);
1216 else if (!pwm->ctx)
1217 return FINISH (GPG_ERR_INV_STATE);
1219 FD_ZERO (&fds);
1220 FD_SET (pwm->fd, &fds);
1221 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1223 if (n == -1)
1224 return FINISH (gpg_error_from_syserror ());
1226 if (n > 0)
1228 if (FD_ISSET (pwm->fd, &fds))
1229 rc = parse_assuan_line (pwm);
1232 while (!rc && assuan_pending_line (pwm->ctx))
1233 rc = parse_assuan_line (pwm);
1235 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1236 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1238 close (pwm->fd);
1239 pwm->fd = -1;
1241 #endif
1243 return FINISH (rc);
1246 static gpg_error_t
1247 status_cb (void *data, const char *line)
1249 pwm_t *pwm = data;
1251 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1252 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1253 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1255 pwmd_free (pwm->passphrase_hint);
1256 pwm->passphrase_hint = pwmd_strdup (line+16);
1258 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1260 pwmd_free (pwm->passphrase_info);
1261 pwm->passphrase_info = pwmd_strdup (line+16);
1263 #ifdef WITH_GNUTLS
1264 else if (!strcmp (line, "REHANDSHAKE"))
1266 char buf[32];
1267 ssize_t ret;
1269 ret = tls_read_hook (pwm, pwm->fd, buf, sizeof (buf));
1270 if (ret < 0)
1272 pwm->tls_error = ret;
1273 return GPG_ERR_GENERAL;
1276 #endif
1278 if (pwm->status_func)
1279 return pwm->status_func (pwm->status_data, line);
1281 return 0;
1284 gpg_error_t
1285 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1286 char **result, size_t * len, const char *cmd)
1288 membuf_t data;
1289 gpg_error_t rc;
1291 if (!cmd || !*cmd)
1292 return FINISH (GPG_ERR_INV_ARG);
1294 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1295 return FINISH (GPG_ERR_LINE_TOO_LONG);
1297 data.len = 0;
1298 data.buf = NULL;
1299 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1300 #ifdef WITH_QUALITY
1301 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1302 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1303 #else
1304 inquire_cb, pwm,
1305 #endif
1306 status_cb, pwm);
1308 if (rc)
1310 if (data.buf)
1312 pwmd_free (data.buf);
1313 data.buf = NULL;
1316 else
1318 if (data.buf)
1320 inquire_realloc_cb (&data, "", 1);
1322 if (result)
1323 *result = (char *) data.buf;
1324 else
1325 pwmd_free (data.buf);
1327 if (len)
1328 *len = data.len;
1332 pwm->inquire_maxlen = 0;
1333 return rc;
1336 gpg_error_t
1337 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1338 pwmd_inquire_cb_t func, void *user, const char *cmd,
1339 va_list ap)
1341 char *buf;
1342 size_t len;
1343 va_list ap2;
1345 if (!pwm)
1346 return GPG_ERR_INV_ARG;
1348 command_start (pwm);
1350 if (result)
1351 *result = NULL;
1353 if (rlen)
1354 *rlen = 0;
1356 if (!pwm || !cmd)
1357 return FINISH (GPG_ERR_INV_ARG);
1358 if (!pwm->ctx)
1359 return FINISH (GPG_ERR_INV_STATE);
1362 * C99 allows the dst pointer to be null which will calculate the length
1363 * of the would-be result and return it.
1365 va_copy (ap2, ap);
1366 len = vsnprintf (NULL, 0, cmd, ap);
1367 buf = (char *) pwmd_malloc (len+1);
1368 if (!buf)
1370 va_end (ap2);
1371 return FINISH (GPG_ERR_ENOMEM);
1374 if (vsnprintf (buf, len+1, cmd, ap2) != len)
1376 pwmd_free (buf);
1377 va_end (ap2);
1378 return FINISH (GPG_ERR_ENOMEM);
1381 if (buf[strlen (buf) - 1] == '\n')
1382 buf[strlen (buf) - 1] = 0;
1383 if (buf[strlen (buf) - 1] == '\r')
1384 buf[strlen (buf) - 1] = 0;
1386 pwm->inquire_func = func;
1387 pwm->inquire_data = user;
1388 pwm->inquire_sent = 0;
1389 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1390 pwmd_free (buf);
1391 return rc;
1394 gpg_error_t
1395 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1396 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1398 va_list ap;
1400 if (result)
1401 *result = NULL;
1403 if (len)
1404 *len = 0;
1406 if (!pwm || !cmd)
1407 return FINISH (GPG_ERR_INV_ARG);
1408 if (!pwm->ctx)
1409 return FINISH (GPG_ERR_INV_STATE);
1411 va_start (ap, cmd);
1412 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1413 va_end (ap);
1414 return rc;
1417 static gpg_error_t
1418 send_pinentry_timeout (pwm_t *pwm)
1420 gpg_error_t rc = 0;
1422 if ((pwm->pinentry_timeout >= 0
1423 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1424 || (pwm->pinentry_timeout == -1
1425 && pwm->pinentry_timeout != pwm->current_pinentry_timeout))
1427 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1428 "OPTION pinentry-timeout=%i",
1429 pwm->pinentry_timeout);
1430 if (!rc)
1431 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1434 return rc;
1437 static gpg_error_t
1438 send_pinentry_options (pwm_t * pwm)
1440 gpg_error_t rc;
1442 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1443 "OPTION disable-pinentry=0");
1444 if (!rc && pwm->pinentry_tty)
1445 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1446 pwm->pinentry_tty);
1448 if (!rc && pwm->pinentry_term)
1449 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1450 pwm->pinentry_term);
1452 if (!rc && pwm->pinentry_display)
1453 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1454 pwm->pinentry_display);
1456 if (!rc && pwm->pinentry_desc)
1457 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1458 pwm->pinentry_desc);
1460 if (!rc && pwm->pinentry_lcctype)
1461 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1462 pwm->pinentry_lcctype);
1464 if (!rc && pwm->pinentry_lcmessages)
1465 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1466 pwm->pinentry_lcmessages);
1468 if (!rc)
1469 rc = send_pinentry_timeout (pwm);
1471 return rc;
1474 gpg_error_t
1475 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1477 if (!pwm || !result)
1478 return FINISH (GPG_ERR_INV_ARG);
1480 *result = PWMD_SOCKET_LOCAL;
1482 if (pwm->fd == -1)
1483 return FINISH (GPG_ERR_INV_STATE);
1485 if (pwm->user_fd)
1487 *result = PWMD_SOCKET_USER;
1488 return 0;
1491 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1492 #ifdef WITH_SSH
1493 if (pwm->tcp && pwm->tcp->ssh)
1494 *result = PWMD_SOCKET_SSH;
1495 #endif
1496 #ifdef WITH_GNUTLS
1497 if (pwm->tcp && pwm->tcp->tls)
1498 *result = PWMD_SOCKET_TLS;
1499 #endif
1500 #endif
1501 return 0;
1504 static gpg_error_t
1505 disable_pinentry (pwm_t *pwm, int *disable)
1507 gpg_error_t rc;
1508 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1509 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1510 #else
1511 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1512 #endif
1514 if (disable)
1515 *disable = no_pinentry;
1517 if (pwm->pinentry_disabled && no_pinentry)
1518 return 0;
1519 else if (!pwm->pinentry_disabled && !no_pinentry)
1520 return 0;
1522 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1523 no_pinentry);
1524 if (!rc)
1525 pwm->pinentry_disabled = no_pinentry;
1527 return rc;
1530 gpg_error_t
1531 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1532 void *data)
1534 gpg_error_t rc = 0;
1535 int no_pinentry = 0;
1537 if (!pwm || !filename || !*filename)
1538 return FINISH (GPG_ERR_INV_ARG);
1540 if (!pwm->ctx)
1541 return FINISH (GPG_ERR_INV_STATE);
1543 command_start (pwm);
1544 rc = disable_pinentry (pwm, &no_pinentry);
1545 if (!rc && !no_pinentry)
1546 rc = send_pinentry_options (pwm);
1548 if (!rc)
1550 pwm->pinentry_try = 0;
1551 pwmd_free (pwm->filename);
1552 pwm->filename = pwmd_strdup (filename);
1556 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1557 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1558 filename);
1560 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1561 && pwm->pinentry_disabled
1562 && ++pwm->pinentry_try < pwm->pinentry_tries);
1564 pwm->pinentry_try = 0;
1566 if (rc)
1568 pwmd_free (pwm->filename);
1569 pwm->filename = NULL;
1573 pwmd_free (pwm->passphrase_hint);
1574 pwmd_free (pwm->passphrase_info);
1575 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1576 return FINISH (rc);
1579 static gpg_error_t
1580 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1581 void *data, int which)
1583 gpg_error_t rc = 0;
1584 int no_pinentry = 0;
1586 if (!pwm)
1587 return FINISH (GPG_ERR_INV_ARG);
1588 if (!pwm->ctx)
1589 return FINISH (GPG_ERR_INV_STATE);
1591 command_start (pwm);
1592 rc = disable_pinentry (pwm, &no_pinentry);
1593 if (!rc && !no_pinentry)
1594 rc = send_pinentry_options (pwm);
1596 if (!rc)
1598 if (which == PWMD_WHICH_SAVE)
1599 rc = pwmd_command (pwm, NULL, NULL, cb, data, "SAVE %s", args ? args : "");
1600 else if (which == PWMD_WHICH_PASSWD)
1601 rc = pwmd_command (pwm, NULL, NULL, cb, data, "PASSWD %s", args ? args : "");
1602 else if (which == PWMD_WHICH_GENKEY)
1603 rc = pwmd_command (pwm, NULL, NULL, cb, data, "GENKEY %s", args ? args : "");
1606 pwmd_free (pwm->passphrase_hint);
1607 pwmd_free (pwm->passphrase_info);
1608 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1609 return FINISH (rc);
1612 gpg_error_t
1613 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1615 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_PASSWD);
1618 gpg_error_t
1619 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1621 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_SAVE);
1624 gpg_error_t
1625 pwmd_genkey (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1627 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_GENKEY);
1630 static gpg_error_t
1631 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1633 int n, *intp;
1634 size_t *sizetp;
1635 char *arg1, **charpp;
1636 gpg_error_t rc = 0;
1638 if (!pwm)
1639 return GPG_ERR_INV_ARG;
1641 command_start (pwm);
1642 switch (opt)
1644 case PWMD_OPTION_SERVER_VERSION:
1645 if (!get)
1646 return GPG_ERR_NOT_SUPPORTED;
1648 if (!pwm->ctx)
1649 rc = GPG_ERR_INV_STATE;
1650 else
1652 unsigned *u = va_arg (ap, unsigned *);
1653 *u = pwm->version;
1656 break;
1657 case PWMD_OPTION_SIGPIPE:
1658 if (get)
1660 intp = va_arg (ap, int *);
1661 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1662 break;
1665 n = va_arg (ap, int);
1666 if (n < 0 || n > 1)
1668 rc = GPG_ERR_INV_VALUE;
1669 break;
1672 if (n)
1673 pwm->opts |= OPT_SIGPIPE;
1674 else
1675 pwm->opts &= ~OPT_SIGPIPE;
1677 break;
1678 case PWMD_OPTION_LOCK_ON_OPEN:
1679 if (get)
1681 intp = va_arg (ap, int *);
1682 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1683 break;
1686 n = va_arg (ap, int);
1687 if (n < 0 || n > 1)
1689 rc = GPG_ERR_INV_VALUE;
1690 break;
1693 if (n)
1694 pwm->opts |= OPT_LOCK_ON_OPEN;
1695 else
1696 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1698 break;
1699 case PWMD_OPTION_INQUIRE_TOTAL:
1700 if (get)
1702 sizetp = va_arg (ap, size_t *);
1703 *sizetp = pwm->inquire_total;
1704 break;
1707 pwm->inquire_total = va_arg (ap, size_t);
1708 break;
1709 case PWMD_OPTION_STATUS_CB:
1710 if (get)
1712 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1714 *cb = pwm->status_func;
1715 break;
1718 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1719 break;
1720 case PWMD_OPTION_STATUS_DATA:
1721 if (get)
1723 void **data = va_arg (ap, void **);
1725 *data = pwm->status_data;
1726 break;
1729 pwm->status_data = va_arg (ap, void *);
1730 break;
1731 case PWMD_OPTION_NO_PINENTRY:
1732 if (get)
1734 intp = va_arg (ap, int *);
1735 *intp = pwm->disable_pinentry;
1736 break;
1739 n = va_arg (ap, int);
1740 if (n < 0 || n > 1)
1741 rc = GPG_ERR_INV_VALUE;
1742 else
1743 pwm->disable_pinentry = n;
1744 break;
1745 case PWMD_OPTION_LOCAL_PINENTRY:
1746 if (get)
1748 intp = va_arg (ap, int *);
1749 *intp = pwm->local_pinentry;
1750 break;
1753 n = va_arg (ap, int);
1754 if (n < 0 || n > 1)
1755 rc = GPG_ERR_INV_VALUE;
1756 else
1757 pwm->local_pinentry = n;
1759 break;
1760 case PWMD_OPTION_PINENTRY_TIMEOUT:
1761 if (get)
1763 intp = va_arg (ap, int *);
1764 *intp = pwm->pinentry_timeout;
1765 break;
1768 n = va_arg (ap, int);
1769 if (n < 0)
1770 rc = GPG_ERR_INV_VALUE;
1771 else
1772 pwm->pinentry_timeout = n;
1773 break;
1774 case PWMD_OPTION_PINENTRY_TRIES:
1775 if (get)
1777 intp = va_arg (ap, int *);
1778 *intp = pwm->pinentry_tries;
1779 break;
1782 n = va_arg (ap, int);
1783 if (n < 0)
1784 rc = GPG_ERR_INV_VALUE;
1785 else
1786 pwm->pinentry_tries = n;
1787 break;
1788 case PWMD_OPTION_PINENTRY_PATH:
1789 if (get)
1791 charpp = va_arg (ap, char **);
1792 *charpp = pwm->pinentry_path;
1793 break;
1796 arg1 = va_arg (ap, char *);
1797 pwmd_free (pwm->pinentry_path);
1798 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1799 break;
1800 case PWMD_OPTION_PINENTRY_TTY:
1801 if (get)
1803 charpp = va_arg (ap, char **);
1804 *charpp = pwm->pinentry_tty;
1805 break;
1808 arg1 = va_arg (ap, char *);
1809 pwmd_free (pwm->pinentry_tty);
1810 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1811 break;
1812 case PWMD_OPTION_PINENTRY_DISPLAY:
1813 if (get)
1815 charpp = va_arg (ap, char **);
1816 *charpp = pwm->pinentry_display;
1817 break;
1820 arg1 = va_arg (ap, char *);
1821 pwmd_free (pwm->pinentry_display);
1822 pwm->pinentry_display = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
1823 if (!pwm->pinentry_display)
1824 unsetenv ("DISPLAY");
1825 break;
1826 case PWMD_OPTION_PINENTRY_TERM:
1827 if (get)
1829 charpp = va_arg (ap, char **);
1830 *charpp = pwm->pinentry_term;
1831 break;
1834 arg1 = va_arg (ap, char *);
1835 pwmd_free (pwm->pinentry_term);
1836 pwm->pinentry_term = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
1837 if (pwm->pinentry_term)
1838 unsetenv ("TERM");
1839 break;
1840 case PWMD_OPTION_PINENTRY_ERROR:
1841 if (get)
1843 charpp = va_arg (ap, char **);
1844 *charpp = pwm->pinentry_error;
1845 break;
1848 arg1 = va_arg (ap, char *);
1849 pwmd_free (pwm->pinentry_error);
1850 if (pwm->disable_pinentry)
1851 pwm->pinentry_error = arg1 ? pwmd_strdup (arg1) : NULL;
1852 else
1853 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1854 break;
1855 case PWMD_OPTION_PINENTRY_PROMPT:
1856 if (get)
1858 charpp = va_arg (ap, char **);
1859 *charpp = pwm->pinentry_prompt;
1860 break;
1863 arg1 = va_arg (ap, char *);
1864 pwmd_free (pwm->pinentry_prompt);
1865 if (pwm->disable_pinentry)
1866 pwm->pinentry_prompt = arg1 ? pwmd_strdup (arg1) : NULL;
1867 else
1868 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1869 break;
1870 case PWMD_OPTION_PINENTRY_DESC:
1871 if (get)
1873 charpp = va_arg (ap, char **);
1874 *charpp = pwm->pinentry_desc;
1875 break;
1878 arg1 = va_arg (ap, char *);
1879 pwmd_free (pwm->pinentry_desc);
1880 if (pwm->disable_pinentry)
1881 pwm->pinentry_desc = arg1 ? pwmd_strdup (arg1) : NULL;
1882 else
1883 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1884 break;
1885 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1886 if (get)
1888 charpp = va_arg (ap, char **);
1889 *charpp = pwm->pinentry_lcctype;
1890 break;
1893 arg1 = va_arg (ap, char *);
1894 pwmd_free (pwm->pinentry_lcctype);
1895 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1896 break;
1897 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1898 if (get)
1900 charpp = va_arg (ap, char **);
1901 *charpp = pwm->pinentry_lcmessages;
1902 break;
1905 arg1 = va_arg (ap, char *);
1906 pwmd_free (pwm->pinentry_lcmessages);
1907 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1908 break;
1909 case PWMD_OPTION_KNOWNHOST_CB:
1910 if (get)
1912 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
1914 *cb = pwm->kh_cb;
1915 break;
1918 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1919 break;
1920 case PWMD_OPTION_KNOWNHOST_DATA:
1921 if (get)
1923 void **data = va_arg (ap, void **);
1925 *data = pwm->kh_data;
1926 break;
1929 pwm->kh_data = va_arg (ap, void *);
1930 break;
1931 case PWMD_OPTION_SSH_AGENT:
1932 if (get)
1934 intp = va_arg (ap, int *);
1935 *intp = pwm->use_agent;
1936 break;
1939 n = va_arg (ap, int);
1940 if (n < 0 || n > 1)
1941 rc = GPG_ERR_INV_VALUE;
1942 else
1943 pwm->use_agent = n;
1944 break;
1945 case PWMD_OPTION_SSH_PASSPHRASE:
1946 if (get)
1947 return GPG_ERR_NOT_SUPPORTED;
1949 pwmd_free (pwm->ssh_passphrase);
1950 pwm->ssh_passphrase = NULL;
1951 arg1 = va_arg (ap, char *);
1952 if (arg1)
1954 pwm->ssh_passphrase = pwmd_strdup (arg1);
1955 if (!pwm->ssh_passphrase)
1956 return GPG_ERR_ENOMEM;
1958 break;
1959 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE:
1960 if (get)
1962 intp = va_arg (ap, int *);
1963 *intp = pwm->needs_passphrase;
1964 break;
1967 n = va_arg (ap, int);
1968 if (n < 0 || n > 1)
1969 rc = GPG_ERR_INV_VALUE;
1970 else
1971 pwm->needs_passphrase = n;
1972 break;
1973 case PWMD_OPTION_TLS_VERIFY:
1974 if (get)
1976 intp = va_arg (ap, int *);
1977 *intp = pwm->tls_verify;
1978 break;
1981 n = va_arg (ap, int);
1982 if (n < 0 || n > 1)
1983 rc = GPG_ERR_INV_VALUE;
1984 else
1985 pwm->tls_verify = n;
1986 break;
1987 case PWMD_OPTION_TLS_PRIORITY:
1988 if (get)
1990 charpp = va_arg (ap, char **);
1991 *charpp = pwm->tls_priority;
1992 break;
1995 pwmd_free (pwm->tls_priority);
1996 pwm->tls_priority = NULL;
1997 arg1 = va_arg (ap, char *);
1998 if (arg1)
2000 pwm->tls_priority = pwmd_strdup (arg1);
2001 if (!pwm->tls_priority)
2002 rc = GPG_ERR_ENOMEM;
2004 break;
2005 case PWMD_OPTION_SOCKET_TIMEOUT:
2006 if (get)
2008 intp = va_arg (ap, int *);
2009 *intp = pwm->socket_timeout;
2010 break;
2013 n = va_arg (ap, int);
2014 if (n < 0)
2016 rc = GPG_ERR_INV_VALUE;
2017 break;
2019 else
2020 pwm->socket_timeout = n;
2022 #ifdef WITH_SSH
2023 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
2025 pwm->tcp->ssh->timeout = pwm->socket_timeout;
2026 libssh2_session_set_timeout (pwm->tcp->ssh->session,
2027 pwm->socket_timeout * 1000);
2029 #endif
2030 #ifdef WITH_GNUTLS
2031 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
2032 pwm->tcp->tls->timeout = pwm->socket_timeout;
2033 #endif
2034 break;
2035 case PWMD_OPTION_READ_CB:
2036 if (get)
2038 pwmd_read_cb_t *cb = va_arg (ap, pwmd_read_cb_t *);
2040 *cb = pwm->read_cb;
2041 break;
2043 pwm->read_cb = va_arg (ap, pwmd_read_cb_t);
2044 break;
2045 case PWMD_OPTION_READ_CB_DATA:
2046 if (get)
2048 void **data = va_arg (ap, void **);
2050 *data = pwm->read_cb_data;
2051 break;
2054 pwm->read_cb_data = va_arg (ap, void *);
2055 break;
2056 case PWMD_OPTION_WRITE_CB:
2057 if (get)
2059 pwmd_write_cb_t *cb = va_arg (ap, pwmd_write_cb_t *);
2061 *cb = pwm->write_cb;
2062 break;
2064 pwm->write_cb = va_arg (ap, pwmd_write_cb_t);
2065 break;
2066 case PWMD_OPTION_WRITE_CB_DATA:
2067 if (get)
2069 void **data = va_arg (ap, void **);
2071 *data = pwm->write_cb_data;
2072 break;
2075 pwm->write_cb_data = va_arg (ap, void *);
2076 break;
2077 case PWMD_OPTION_OVERRIDE_INQUIRE:
2078 if (get)
2080 intp = va_arg (ap, int *);
2081 *intp = pwm->override_inquire;
2082 break;
2085 n = va_arg (ap, int);
2086 if (n < 0 || n > 1)
2087 rc = GPG_ERR_INV_VALUE;
2088 else
2089 pwm->override_inquire = n;
2090 break;
2091 default:
2092 rc = GPG_ERR_UNKNOWN_OPTION;
2093 break;
2096 return FINISH (rc);
2099 gpg_error_t
2100 pwmd_setopt (pwm_t * pwm, int opt, ...)
2102 va_list ap;
2103 gpg_error_t rc = 0;
2105 va_start (ap, opt);
2106 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
2107 va_end (ap);
2108 return FINISH (rc);
2111 gpg_error_t
2112 pwmd_getopt (pwm_t *pwm, int opt, ...)
2114 va_list ap;
2115 gpg_error_t rc = 0;
2117 va_start (ap, opt);
2118 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
2119 va_end (ap);
2120 return FINISH (rc);
2123 gpg_error_t
2124 set_rcdefaults (pwm_t *pwm, char *filename)
2126 char *f;
2127 FILE *fp;
2128 char *line = NULL, *p;
2129 unsigned line_n = 0;
2130 gpg_error_t rc = 0;
2132 if (!filename && isatty (STDIN_FILENO))
2134 char buf[256];
2135 int err = ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
2137 if (!err)
2139 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, buf);
2140 if (rc)
2141 return rc;
2143 if (getenv ("TERM"))
2145 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, getenv ("TERM"));
2146 if (rc)
2147 return rc;
2152 if (!filename && getenv ("DISPLAY"))
2154 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, getenv ("DISPLAY"));
2155 if (rc)
2156 return rc;
2159 f = _expand_homedir (filename ? filename : (char *)"~/.config/libpwmd.conf",
2160 NULL);
2161 if (f)
2163 line = pwmd_malloc (LINE_MAX);
2164 if (line)
2166 fp = fopen (f, "r");
2167 if (!fp)
2169 pwmd_free (line);
2170 pwmd_free (f);
2171 return 0;
2174 else
2175 rc = GPG_ERR_ENOMEM;
2177 else
2178 rc = GPG_ERR_ENOMEM;
2180 if (rc)
2182 pwmd_free (f);
2183 pwmd_free (line);
2184 return rc;
2187 while ((p = fgets (line, LINE_MAX, fp)))
2189 char name[32] = {0}, val[512] = {0};
2190 char *np;
2191 char *t;
2192 size_t len = 0;
2194 line_n++;
2196 while (isspace (*p))
2197 p++;
2199 if (!*p || *p == '#')
2200 continue;
2202 if (p[strlen (p)-1] == '\n')
2203 p[strlen (p)-1] = 0;
2205 t = strchr (p, '=');
2206 if (!t)
2208 fprintf(stderr, N_("%s(%u): malformed line\n"), f, line_n);
2209 continue;
2212 for (np = name; p != t; p++)
2214 if (++len == sizeof (name))
2215 break;
2217 if (isspace (*p))
2218 break;
2220 *np++ = *p;
2223 while (isspace (*t))
2224 t++;
2225 t++; // '='
2226 while (isspace (*t))
2227 t++;
2229 strncpy (val, t, sizeof (val)-1);
2231 if (!strcasecmp (name, "pinentry-path"))
2232 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, val);
2233 else if (!strcasecmp (name, "pinentry-tries"))
2234 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, atoi (val));
2235 else if (!strcasecmp (name, "pinentry-timeout"))
2236 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, atoi (val));
2237 else if (!strcasecmp (name, "no-pinentry"))
2238 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, !!(atoi (val)));
2239 else if (!strcasecmp (name, "local-pinentry"))
2240 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, !!(atoi (val)));
2241 else if (!strcasecmp (name, "pinentry-display"))
2242 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, val);
2243 else if (!strcasecmp (name, "pinentry-ttyname"))
2244 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, val);
2245 else if (!strcasecmp (name, "pinentry-ttytype"))
2246 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, val);
2247 else if (!strcasecmp (name, "pinentry-lc-messages"))
2248 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, val);
2249 else if (!strcasecmp (name, "pinentry-lc-ctype"))
2250 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, val);
2251 else if (!strcasecmp (name, "no-ssh-agent"))
2252 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, !(atoi (val)));
2253 else if (!strcasecmp (name, "no-tls-verify"))
2254 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, !(atoi (val)));
2255 else if (!strcasecmp (name, "tls-priority"))
2256 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, val);
2257 else if (!strcasecmp (name, "socket-timeout"))
2258 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, atoi (val));
2259 else if (!strcasecmp (name, "no-lock"))
2260 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, !(atoi (val)));
2261 else if (!strcasecmp (name, "include"))
2262 rc = set_rcdefaults (pwm, val);
2263 else
2264 fprintf(stderr, N_("%s(%u): invalid option '%s', ignored.\n"), f,
2265 line_n, name);
2267 if (rc)
2268 break;
2271 fclose (fp);
2272 pwmd_free (line);
2273 pwmd_free (f);
2274 return rc;
2277 gpg_error_t
2278 pwmd_new (const char *name, pwm_t ** pwm)
2280 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
2281 gpg_error_t rc;
2283 if (!h)
2284 return FINISH (GPG_ERR_ENOMEM);
2286 if (name)
2288 h->name = pwmd_strdup (name);
2289 if (!h->name)
2291 pwmd_free (h);
2292 return FINISH (GPG_ERR_ENOMEM);
2296 reset_handle (h);
2297 h->pinentry_timeout = -1;
2298 h->current_pinentry_timeout = -1;
2299 h->pinentry_tries = 3;
2300 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2301 h->prot = PWMD_IP_ANY;
2302 h->socket_timeout = 120;
2303 h->tls_verify = 1;
2304 #endif
2305 h->opts |= OPT_LOCK_ON_OPEN;
2307 rc = set_rcdefaults (h, NULL);
2308 if (rc)
2309 goto fail;
2311 *pwm = h;
2312 return 0;
2314 fail:
2315 pwmd_close (h);
2316 return FINISH (rc);
2319 void
2320 pwmd_free (void *ptr)
2322 _xfree (ptr);
2325 void *
2326 pwmd_malloc (size_t size)
2328 return _xmalloc (size);
2331 void *
2332 pwmd_calloc (size_t nmemb, size_t size)
2334 return _xcalloc (nmemb, size);
2337 void *
2338 pwmd_realloc (void *ptr, size_t size)
2340 return _xrealloc (ptr, size);
2343 char *
2344 pwmd_strdup (const char *str)
2346 char *t;
2347 size_t len;
2348 register size_t c;
2350 len = strlen (str);
2351 t = _xmalloc ((len + 1) * sizeof (char));
2352 if (!t)
2353 return NULL;
2355 for (c = 0; c < len; c++)
2356 t[c] = str[c];
2358 t[c] = 0;
2359 return t;
2362 char *
2363 pwmd_strdup_printf (const char *fmt, ...)
2365 va_list ap, ap2;
2366 int len;
2367 char *buf;
2369 if (!fmt)
2370 return NULL;
2372 va_start (ap, fmt);
2373 va_copy (ap2, ap);
2374 len = vsnprintf (NULL, 0, fmt, ap);
2375 va_end (ap);
2376 buf = pwmd_malloc (++len);
2377 if (buf)
2378 vsnprintf (buf, len, fmt, ap2);
2380 va_end (ap2);
2381 return buf;
2384 gpg_error_t
2385 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
2386 size_t * len, pwmd_pinentry_t which)
2388 #ifndef WITH_PINENTRY
2389 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
2390 #else
2391 gpg_error_t rc;
2393 command_start (pwm);
2394 if (which == PWMD_PINENTRY_CONFIRM && pwm->disable_pinentry)
2396 rc = get_password (pwm, NULL, NULL, which, 1);
2397 return FINISH (rc);
2400 rc = _pwmd_getpin (pwm, filename, result, len, which);
2401 return FINISH (rc);
2402 #endif
2405 const char *
2406 pwmd_version ()
2408 return LIBPWMD_VERSION_STR;
2411 unsigned int
2412 pwmd_features ()
2414 unsigned int n = 0;
2416 #ifdef WITH_PINENTRY
2417 n |= PWMD_FEATURE_PINENTRY;
2418 #endif
2419 #ifdef WITH_SSH
2420 n |= PWMD_FEATURE_SSH;
2421 #endif
2422 #ifdef WITH_QUALITY
2423 n |= PWMD_FEATURE_QUALITY;
2424 #endif
2425 #ifdef WITH_GNUTLS
2426 n |= PWMD_FEATURE_GNUTLS;
2427 #endif
2428 return n;
2431 gpg_error_t
2432 pwmd_fd (pwm_t * pwm, int *fd)
2434 if (!pwm || !fd)
2435 return FINISH (GPG_ERR_INV_ARG);
2437 if (pwm->fd == -1)
2438 return FINISH (GPG_ERR_INV_STATE);
2440 *fd = pwm->fd;
2441 return 0;
2444 void
2445 pwmd_set_pointer (pwm_t *pwm, void *data)
2447 pwm->user_data = data;
2450 void *
2451 pwmd_get_pointer (pwm_t *pwm)
2453 return pwm->user_data;
2457 pwmd_gnutls_error (pwm_t *pwm, const char **str)
2459 #ifndef WITH_GNUTLS
2460 (void)pwm;
2461 (void)str;
2462 return 0;
2463 #else
2464 if (str && pwm && pwm->tls_error)
2465 *str = gnutls_strerror (pwm->tls_error);
2467 return pwm ? pwm->tls_error : 0;
2468 #endif
2471 gpg_error_t
2472 pwmd_cancel (pwm_t *pwm)
2474 if (!pwm)
2475 return FINISH (GPG_ERR_INV_ARG);
2477 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2478 if (pwm->fd == -1 && !pwm->tcp)
2479 #else
2480 if (pwm->fd == -1)
2481 #endif
2482 return FINISH (GPG_ERR_INV_STATE);
2484 /* Can only cancel the connection for the time being. */
2485 if (pwm->connected)
2486 return FINISH (GPG_ERR_INV_STATE);
2488 pwm->cancel = 1;
2489 return 0;
2492 gpg_error_t
2493 pwmd_test_quality (const char *str, double *result)
2495 #ifndef WITH_QUALITY
2496 (void)str;
2497 (void)result;
2498 return GPG_ERR_NOT_IMPLEMENTED;
2499 #else
2500 if (!result)
2501 return GPG_ERR_INV_ARG;
2503 *result = ZxcvbnMatch (str, NULL, NULL);
2504 return 0;
2505 #endif