Handle cancellation in pwmd_connect ().
[libpwmd.git] / src / libpwmd.c
blob393ac2cba7b2c91dafefd18c22ac369ae51085ab
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <err.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <sys/wait.h>
38 #include <fcntl.h>
39 #include <pwd.h>
40 #include <time.h>
41 #include <limits.h>
42 #include <sys/select.h>
43 #include <termios.h>
44 #include <libpwmd.h>
46 #ifdef HAVE_STRINGS_H
47 #include <strings.h>
48 #endif
50 #ifndef LINE_MAX
51 #define LINE_MAX 2048
52 #endif
54 #include "mem.h"
55 #include "misc.h"
56 #include "types.h"
58 #ifdef WITH_PINENTRY
59 #include "pinentry.h"
60 #endif
62 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <netdb.h>
66 #include <netinet/in.h>
67 #endif
69 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
70 ? gpg_error(rc) : rc
72 typedef struct
74 size_t len;
75 void *buf;
76 } membuf_t;
78 ssize_t
79 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
81 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
82 pwm_t *pwm = assuan_get_pointer (ctx);
84 #ifdef WITH_SSH
85 if (pwm && pwm->tcp && pwm->tcp->ssh)
86 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
87 #endif
88 #ifdef WITH_GNUTLS
89 if (pwm && pwm->tcp && pwm->tcp->tls)
90 return read_hook_tls (pwm, fd, data, len);
91 #endif
92 #endif
94 return read ((int) fd, data, len);
97 ssize_t
98 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
99 size_t len)
101 ssize_t wrote;
102 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
103 pwm_t *pwm = assuan_get_pointer (ctx);
105 #ifdef WITH_SSH
106 if (pwm && pwm->tcp && pwm->tcp->ssh)
107 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
108 #endif
109 #ifdef WITH_GNUTLS
110 if (pwm && pwm->tcp && pwm->tcp->tls)
111 return write_hook_tls (pwm, fd, data, len);
112 #endif
113 #endif
115 /* libassuan cannot handle EAGAIN when doing writes. */
118 wrote = write ((int) fd, data, len);
119 if (wrote == -1 && errno == EAGAIN)
120 usleep (50000);
122 while (wrote == -1 && errno == EAGAIN);
124 return wrote;
127 pid_t
128 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
129 int options)
131 return waitpid (pid, status, options);
134 gpg_error_t
135 pwmd_init ()
137 static int initialized;
139 #ifdef WITH_GNUTLS
140 // May be called more than once.
141 gnutls_global_init ();
142 #endif
144 if (initialized)
145 return 0;
147 #ifndef MEM_DEBUG
148 _xmem_init ();
149 #endif
150 #ifdef ENABLE_NLS
151 bindtextdomain ("libpwmd", LOCALEDIR);
152 #endif
153 #ifdef WITH_SSH
154 libssh2_init (0);
155 #endif
156 gpg_err_init ();
157 initialized = 1;
158 return 0;
161 void
162 pwmd_deinit ()
164 #ifdef WITH_GNUTLS
165 gnutls_global_deinit ();
166 #endif
169 gpg_error_t
170 _connect_finalize (pwm_t * pwm)
172 gpg_error_t rc = 0;
173 char *result = NULL;
174 int active[2];
175 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
177 if (n <= 0)
178 return GPG_ERR_EBADFD;
180 pwm->fd = active[0];
181 #ifdef WITH_PINENTRY
182 pwm->pinentry_pid = -1;
183 #endif
185 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "GETINFO VERSION");
186 if (!rc)
188 pwm->version = strtoul (result, NULL, 16);
189 pwmd_free (result);
192 if (!rc && pwm->name)
193 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
194 pwm->name);
196 return rc;
199 static gpg_error_t
200 connect_uds (pwm_t * pwm, const char *path)
202 char *socketpath = NULL;
203 struct passwd pw;
204 char *pwbuf;
205 gpg_error_t rc;
207 if (!pwm)
208 return GPG_ERR_INV_ARG;
210 pwbuf = _getpwuid (&pw);
211 if (!pwbuf)
212 return gpg_error_from_syserror ();
214 if (!path || !*path)
215 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
216 else
217 socketpath = _expand_homedir ((char *) path, &pw);
219 pwmd_free (pwbuf);
220 if (!socketpath)
221 return GPG_ERR_ENOMEM;
223 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
224 pwmd_free (socketpath);
225 return rc ? rc : _connect_finalize (pwm);
228 static gpg_error_t
229 init_handle (pwm_t * pwm)
231 gpg_error_t rc;
232 static struct assuan_malloc_hooks mhooks = {
233 pwmd_malloc, pwmd_realloc, pwmd_free
235 static struct assuan_system_hooks shooks = {
236 ASSUAN_SYSTEM_HOOKS_VERSION,
237 __assuan_usleep,
238 __assuan_pipe,
239 __assuan_close,
240 hook_read,
241 hook_write,
242 //FIXME
243 NULL, //recvmsg
244 NULL, //sendmsg both are used for FD passing
245 __assuan_spawn,
246 hook_waitpid,
247 __assuan_socketpair,
248 __assuan_socket,
249 __assuan_connect
252 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
253 NULL);
254 if (rc)
255 return rc;
257 assuan_set_pointer (pwm->ctx, pwm);
258 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
259 return 0;
262 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
263 void
264 free_tcp (pwm_t *pwm)
266 struct tcp_s *tcp = pwm->tcp;
268 if (!tcp)
269 return;
271 #ifdef WITH_SSH
272 _free_ssh_conn (tcp->ssh);
273 #endif
274 #ifdef WITH_GNUTLS
275 tls_free (pwm);
276 #endif
278 pwmd_free (tcp->host);
279 if (tcp->addrs)
281 freeaddrinfo (tcp->addrs);
282 tcp->addrs = NULL;
285 pwmd_free (tcp);
286 pwm->tcp = NULL;
288 #endif
290 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
291 gpg_error_t
292 tcp_connect_common (pwm_t * pwm)
294 struct addrinfo hints = { 0 };
295 int n;
296 char portstr[6];
297 gpg_error_t rc = 0;
299 switch (pwm->prot)
301 case PWMD_IP_ANY:
302 hints.ai_family = AF_UNSPEC;
303 break;
304 case PWMD_IPV4:
305 hints.ai_family = AF_INET;
306 break;
307 case PWMD_IPV6:
308 hints.ai_family = AF_INET6;
309 break;
312 hints.ai_socktype = SOCK_STREAM;
313 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
314 n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
315 if (n)
317 fprintf (stderr, "%s\n", gai_strerror (n));
318 return GPG_ERR_UNKNOWN_HOST; //FIXME
321 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
322 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
324 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
325 if (pwm->fd == -1)
327 rc = gpg_error_from_syserror ();
328 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
329 break;
330 continue;
333 if (fcntl (pwm->fd, F_SETFL, O_NONBLOCK) == -1)
335 rc = gpg_error_from_syserror ();
336 break;
339 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
340 pwm->tcp->addr->ai_family == AF_INET6
341 ? sizeof (struct sockaddr_in6)
342 : sizeof (struct sockaddr)) == -1)
344 int n;
345 struct timeval tv;
346 fd_set wfds;
347 unsigned elapsed = 0;
349 rc = gpg_error_from_syserror ();
350 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
352 close (pwm->fd);
353 pwm->fd = -1;
354 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
355 return rc;
356 continue;
359 again:
360 tv.tv_sec = 1;
361 tv.tv_usec = 0;
362 FD_ZERO (&wfds);
363 FD_SET (pwm->fd, &wfds);
364 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
365 rc = 0;
366 if (!n || pwm->cancel)
368 if (pwm->cancel)
369 rc = gpg_error (GPG_ERR_CANCELED);
370 else if (++elapsed >= pwm->socket_timeout)
371 rc = gpg_error (GPG_ERR_ETIMEDOUT);
372 else
373 goto again;
375 else if (n != -1)
377 socklen_t len = sizeof(int);
379 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
380 if (n)
381 rc = gpg_error_from_errno (n);
383 else if (n == -1)
384 rc = gpg_error_from_syserror ();
386 if (rc)
388 close (pwm->fd);
389 pwm->fd = -1;
390 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
391 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
392 || pwm->cancel)
393 return rc;
395 else
396 break;
398 else
399 break;
402 if (!rc)
403 if (fcntl (pwm->fd, F_SETFL, 0) == -1)
404 rc = gpg_error_from_syserror ();
406 return rc;
408 #endif
410 static void
411 command_start (pwm_t *pwm)
413 pwm->cancel = 0;
416 gpg_error_t
417 pwmd_connect (pwm_t * pwm, const char *url, ...)
419 const char *p = url;
420 gpg_error_t rc;
422 if (!pwm)
423 return FINISH (GPG_ERR_INV_ARG);
424 else if (!pwm->ctx)
426 rc = init_handle (pwm);
427 if (rc)
428 return rc;
431 command_start (pwm);
433 if (!(pwm->opts & OPT_SIGPIPE))
434 signal (SIGPIPE, SIG_IGN);
436 #ifdef WITH_GNUTLS
437 pwm->tls_error = 0;
438 #endif
439 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
441 if (p && (*p == '/' || *p == '~'))
442 rc = connect_uds (pwm, p);
443 else if (!p || !strncmp (p, "file://", 7))
445 if (p)
446 p += 7;
447 #ifdef DEFAULT_PWMD_SOCKET
448 else
449 p = DEFAULT_PWMD_SOCKET;
450 #endif
451 rc = connect_uds (pwm, p);
453 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
454 !strncmp (p, "ssh4://", 7))
456 #ifndef WITH_SSH
457 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
458 #else
459 char *host = NULL;
460 int port;
461 char *username = NULL;
463 if (!strncmp (p, "ssh6://", 7))
465 pwm->prot = PWMD_IPV6;
466 p += 7;
468 else if (!strncmp (p, "ssh4://", 7))
470 pwm->prot = PWMD_IPV4;
471 p += 7;
473 else
475 pwm->prot = PWMD_IP_ANY;
476 p += 6;
479 rc = _parse_ssh_url (p, &host, &port, &username);
480 if (!rc)
482 va_list ap;
483 char *identity = NULL;
484 char *knownhosts = NULL;
486 va_start (ap, url);
487 identity = va_arg (ap, char *);
489 if (!identity && !pwm->use_agent)
490 rc = GPG_ERR_INV_ARG;
491 else
492 knownhosts = va_arg (ap, char *);
494 va_end (ap);
496 if (!rc)
497 rc = _do_ssh_connect (pwm, host, port, identity, username,
498 knownhosts);
499 if (!rc)
501 rc = _connect_finalize (pwm);
502 if (rc)
503 free_tcp (pwm);
507 pwmd_free (host);
508 pwmd_free (username);
509 pwm->local_pinentry = 1;
510 #endif
512 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
513 !strncmp (p, "tls4://", 7))
515 #ifndef WITH_GNUTLS
516 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
517 #else
518 char *host = NULL;
519 int port;
521 if (!strncmp (p, "tls6://", 7))
523 pwm->prot = PWMD_IPV6;
524 p += 7;
526 else if (!strncmp (p, "tls4://", 7))
528 pwm->prot = PWMD_IPV4;
529 p += 7;
531 else
533 pwm->prot = PWMD_IP_ANY;
534 p += 6;
537 rc = _parse_tls_url (p, &host, &port);
538 if (!rc)
540 va_list ap;
541 char *clientcert = NULL;
542 char *clientkey = NULL;
543 char *cacert = NULL;
544 char *prio = NULL;
545 char *server_fp = NULL;
547 va_start (ap, url);
548 clientcert = va_arg (ap, char *);
550 if (!clientcert)
551 rc = GPG_ERR_INV_ARG;
552 else
554 clientkey = va_arg (ap, char *);
555 if (!clientkey)
556 rc = GPG_ERR_INV_ARG;
557 else
559 cacert = va_arg (ap, char *);
560 if (!cacert)
561 rc = GPG_ERR_INV_ARG;
562 else
564 prio = va_arg (ap, char *);
565 server_fp = va_arg (ap, char *);
570 va_end (ap);
572 if (!rc)
573 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
574 cacert, prio, server_fp, pwm->tls_verify);
575 if (!rc)
577 rc = _connect_finalize (pwm);
578 if (rc)
579 free_tcp (pwm);
583 pwmd_free (host);
584 pwm->local_pinentry = 1;
585 #endif
588 if (!rc)
589 pwm->connected = 1;
591 return FINISH (rc);
594 static void
595 disconnect (pwm_t * pwm)
597 if (!pwm)
598 return;
600 if (pwm->ctx)
601 assuan_release (pwm->ctx);
603 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
604 free_tcp (pwm);
605 #endif
606 pwm->ctx = NULL;
607 pwm->fd = -1;
608 pwm->connected = 0;
611 void
612 pwmd_close (pwm_t * pwm)
614 if (!pwm)
615 return;
617 disconnect (pwm);
618 pwmd_free (pwm->pinentry_error);
619 pwmd_free (pwm->pinentry_desc);
620 pwmd_free (pwm->pinentry_prompt);
621 pwmd_free (pwm->pinentry_tty);
622 pwmd_free (pwm->pinentry_display);
623 pwmd_free (pwm->pinentry_term);
624 pwmd_free (pwm->pinentry_lcctype);
625 pwmd_free (pwm->pinentry_lcmessages);
626 pwmd_free (pwm->filename);
627 pwmd_free (pwm->name);
628 pwmd_free (pwm->passphrase_info);
629 pwmd_free (pwm->passphrase_hint);
631 #ifdef WITH_PINENTRY
632 if (pwm->pctx)
633 _pinentry_disconnect (pwm);
634 #endif
636 pwmd_free (pwm);
639 static gpg_error_t
640 inquire_realloc_cb (void *data, const void *buffer, size_t len)
642 membuf_t *mem = (membuf_t *) data;
643 void *p;
645 if (!buffer)
646 return 0;
648 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
649 return gpg_error (GPG_ERR_ENOMEM);
651 mem->buf = p;
652 memcpy ((char *) mem->buf + mem->len, buffer, len);
653 mem->len += len;
654 return 0;
657 static gpg_error_t
658 get_password (pwm_t * pwm, char **result, size_t * len,
659 pwmd_pinentry_t w, int echo)
661 char buf[LINE_MAX] = { 0 }, *p;
662 struct termios told, tnew;
663 char *key = NULL;
665 if (result)
666 *result = NULL;
668 if (len)
669 *len = 0;
671 if (!isatty (STDIN_FILENO))
673 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
674 return GPG_ERR_ENOTTY;
677 if (!echo)
679 if (tcgetattr (STDIN_FILENO, &told) == -1)
680 return gpg_error_from_syserror ();
682 memcpy (&tnew, &told, sizeof (struct termios));
683 tnew.c_lflag &= ~(ECHO);
684 tnew.c_lflag |= ICANON | ECHONL;
686 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
688 int n = errno;
690 tcsetattr (STDIN_FILENO, TCSANOW, &told);
691 return gpg_error_from_errno (n);
695 switch (w)
697 case PWMD_PINENTRY_OPEN:
698 fprintf (stderr, N_("Password for %s: "), pwm->filename);
699 break;
700 case PWMD_PINENTRY_OPEN_FAILED:
701 fprintf (stderr, N_("Invalid password. Password for %s: "),
702 pwm->filename);
703 break;
704 case PWMD_PINENTRY_SAVE:
705 fprintf (stderr, N_("New password for %s: "), pwm->filename);
706 break;
707 case PWMD_PINENTRY_SAVE_CONFIRM:
708 fprintf (stderr, N_("Confirm password: "));
709 break;
710 default:
711 break;
714 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
716 if (!echo)
717 tcsetattr (STDIN_FILENO, TCSANOW, &told);
718 return 0;
721 if (!echo)
722 tcsetattr (STDIN_FILENO, TCSANOW, &told);
724 if (feof (stdin))
726 clearerr (stdin);
727 return GPG_ERR_CANCELED;
730 /* Strip the newline character. */
731 p[strlen (p) - 1] = 0;
733 if (buf[0])
735 key = pwmd_strdup_printf ("%s", p);
736 memset (buf, 0, sizeof (buf));
737 if (!key)
738 return GPG_ERR_ENOMEM;
740 if (result)
741 *result = key;
743 if (len)
744 *len = strlen (key);
746 else
748 if (result)
749 *result = pwmd_strdup ("");
751 if (len)
752 *len = 1;
755 return 0;
758 gpg_error_t
759 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
761 gpg_error_t rc;
762 int new_password = 0;
763 char *password = NULL, *newpass = NULL;
764 int error = 0;
766 command_start (pwm);
768 if (data)
769 *data = NULL;
771 if (size)
772 *size = 0;
774 if (!strcmp (keyword, "NEW_PASSPHRASE"))
775 new_password = 1;
777 if (!new_password && pwm->pinentry_try)
778 error = 1;
780 again:
781 if (pwm->disable_pinentry)
783 rc = get_password (pwm, &password, size,
784 new_password ? PWMD_PINENTRY_SAVE :
785 error ? PWMD_PINENTRY_OPEN_FAILED :
786 PWMD_PINENTRY_OPEN, 0);
787 if (!rc && new_password)
788 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
791 else
793 pwmd_pinentry_t which;
795 if (error)
796 which = new_password
797 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
798 else
799 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
801 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
802 if (!rc && new_password)
803 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
804 PWMD_PINENTRY_SAVE_CONFIRM);
807 if (!rc && new_password)
809 if ((!password && newpass) || (!newpass && password)
810 || (newpass && password && strcmp (newpass, password)))
812 if (pwm->disable_pinentry)
813 fprintf (stderr, N_("Passphrases do not match.\n"));
815 pwmd_free (password);
816 pwmd_free (newpass);
817 password = newpass = NULL;
818 error = 1;
819 goto again;
823 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
824 pwmd_free (newpass);
825 if (!rc && data)
826 *data = password;
828 return rc;
831 static gpg_error_t
832 inquire_cb (void *data, const char *keyword)
834 pwm_t *pwm = (pwm_t *) data;
835 gpg_error_t rc = 0;
836 int free_result = 0;
837 char *result = NULL;
838 int is_password = 0;
839 int new_password = 0;
841 if (!strcmp (keyword, "PASSPHRASE"))
842 is_password = 1;
843 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
844 new_password = 1;
846 /* Shouldn't get this far without a callback. */
847 if (!pwm->override_inquire && !pwm->inquire_func
848 && !is_password && !new_password)
849 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
851 for (;;)
853 size_t len = 0;
854 gpg_error_t arc;
856 result = NULL;
858 if (!pwm->override_inquire && (is_password || new_password))
860 free_result = 1;
861 rc = pwmd_password (data, keyword, &result, &len);
862 if (!rc)
863 rc = GPG_ERR_EOF;
865 else
866 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
867 &len);
869 /* gpg will truncate a passphrase at the first nil byte which may be bad
870 * for generated key files. */
871 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
872 && (is_password || new_password))
874 if (len && result && *result)
876 for (size_t n = 0; n < len; n++)
878 if (result[n] == 0 && n+1 != len)
879 rc = GPG_ERR_INV_PASSPHRASE;
884 cancel:
885 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
887 #ifndef LIBASSUAN_2_1_0
888 gpg_error_t trc = rc;
890 /* Cancel this inquire. */
891 rc = assuan_send_data (pwm->ctx, NULL, 1);
892 if (!rc)
894 char *line;
895 size_t len;
897 /* There is a bug (or feature?) in assuan_send_data() that
898 * when cancelling an inquire the next read from the server is
899 * not done until the next command making the next command
900 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
902 rc = assuan_read_line (pwm->ctx, &line, &len);
904 /* Restore the original error. This differs from the error
905 * returned from the pwmd command (GPG_ERR_CANCELED). This
906 * error is returned to the calling function.
908 if (!rc)
909 rc = trc;
911 #endif
912 break;
915 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
917 if (len <= 0 && !result)
919 rc = 0;
920 break;
922 else if ((len <= 0 && result) || (len && !result))
924 rc = gpg_error (GPG_ERR_INV_ARG);
925 break;
928 if (pwm->inquire_maxlen
929 && pwm->inquire_sent + len > pwm->inquire_maxlen)
931 rc = gpg_error (GPG_ERR_TOO_LARGE);
932 if (!free_result)
933 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
934 &result, &len);
935 goto cancel;
938 arc = assuan_send_data (pwm->ctx, result, len);
939 if (gpg_err_code (rc) == GPG_ERR_EOF)
941 rc = arc;
942 break;
945 rc = arc;
947 else if (rc)
948 break;
950 if (!rc)
952 pwm->inquire_sent += len;
954 if (pwm->status_func)
956 char buf[ASSUAN_LINELENGTH];
958 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
959 pwm->inquire_total);
960 rc = pwm->status_func (pwm->status_data, buf);
961 if (rc)
962 continue;
967 if (free_result)
968 pwmd_free (result);
970 return rc;
973 static gpg_error_t
974 parse_assuan_line (pwm_t * pwm)
976 gpg_error_t rc;
977 char *line;
978 size_t len;
980 rc = assuan_read_line (pwm->ctx, &line, &len);
981 if (!rc)
983 if (line[0] == 'O' && line[1] == 'K' &&
984 (line[2] == 0 || line[2] == ' '))
987 else if (line[0] == '#')
990 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
992 if (pwm->status_func)
994 rc = pwm->status_func (pwm->status_data,
995 line[1] == 0 ? line + 1 : line + 2);
998 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
999 (line[3] == 0 || line[3] == ' '))
1001 line += 4;
1002 rc = strtol (line, NULL, 10);
1006 return rc;
1009 static void
1010 reset_handle (pwm_t *pwm)
1012 pwm->fd = -1;
1013 pwm->cancel = 0;
1014 pwm->pinentry_disabled = 0;
1015 #ifdef WITH_PINENTRY
1016 if (pwm->pctx)
1017 _pinentry_disconnect (pwm);
1018 #endif
1019 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1020 #ifdef WITH_GNUTLS
1021 pwm->tls_error = 0;
1022 #endif
1024 if (pwm->tcp)
1025 pwm->tcp->rc = 0;
1026 #endif
1029 gpg_error_t
1030 pwmd_disconnect (pwm_t * pwm)
1032 if (!pwm)
1033 return FINISH (GPG_ERR_INV_ARG);
1035 command_start (pwm);
1037 if (pwm->fd == -1)
1038 return FINISH (GPG_ERR_INV_STATE);
1040 disconnect (pwm);
1041 reset_handle (pwm);
1042 return 0;
1045 /* Note that this should only be called when not in a command. */
1046 gpg_error_t
1047 pwmd_process (pwm_t * pwm)
1049 gpg_error_t rc = 0;
1050 fd_set fds;
1051 struct timeval tv = { 0, 0 };
1052 int n;
1054 if (!pwm || pwm->fd == -1)
1055 return FINISH (GPG_ERR_INV_ARG);
1056 else if (!pwm->ctx)
1057 return FINISH (GPG_ERR_INV_STATE);
1059 FD_ZERO (&fds);
1060 FD_SET (pwm->fd, &fds);
1061 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1063 if (n == -1)
1064 return FINISH (gpg_error_from_syserror ());
1066 if (n > 0)
1068 if (FD_ISSET (pwm->fd, &fds))
1069 rc = parse_assuan_line (pwm);
1072 while (!rc && assuan_pending_line (pwm->ctx))
1073 rc = parse_assuan_line (pwm);
1075 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1076 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1078 close (pwm->fd);
1079 pwm->fd = -1;
1081 #endif
1083 return FINISH (rc);
1086 static gpg_error_t
1087 status_cb (void *data, const char *line)
1089 pwm_t *pwm = data;
1091 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1092 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1093 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1095 pwmd_free (pwm->passphrase_hint);
1096 pwm->passphrase_hint = pwmd_strdup (line+16);
1098 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1100 pwmd_free (pwm->passphrase_info);
1101 pwm->passphrase_info = pwmd_strdup (line+16);
1104 if (pwm->status_func)
1105 return pwm->status_func (pwm->status_data, line);
1107 return 0;
1110 gpg_error_t
1111 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1112 char **result, size_t * len, const char *cmd)
1114 membuf_t data;
1115 gpg_error_t rc;
1117 if (!cmd || !*cmd)
1118 return FINISH (GPG_ERR_INV_ARG);
1120 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1121 return FINISH (GPG_ERR_LINE_TOO_LONG);
1123 data.len = 0;
1124 data.buf = NULL;
1125 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1126 #ifdef WITH_QUALITY
1127 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1128 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1129 #else
1130 inquire_cb, pwm,
1131 #endif
1132 status_cb, pwm);
1134 if (rc)
1136 if (data.buf)
1138 pwmd_free (data.buf);
1139 data.buf = NULL;
1142 else
1144 if (data.buf)
1146 inquire_realloc_cb (&data, "", 1);
1148 if (result)
1149 *result = (char *) data.buf;
1150 else
1151 pwmd_free (data.buf);
1153 if (len)
1154 *len = data.len;
1158 pwm->inquire_maxlen = 0;
1159 return rc;
1162 gpg_error_t
1163 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1164 pwmd_inquire_cb_t func, void *user, const char *cmd,
1165 va_list ap)
1167 char *buf;
1168 size_t len;
1169 va_list ap2;
1171 command_start (pwm);
1173 if (result)
1174 *result = NULL;
1176 if (rlen)
1177 *rlen = 0;
1179 if (!pwm || !cmd)
1180 return FINISH (GPG_ERR_INV_ARG);
1181 if (!pwm->ctx)
1182 return FINISH (GPG_ERR_INV_STATE);
1185 * C99 allows the dst pointer to be null which will calculate the length
1186 * of the would-be result and return it.
1188 va_copy (ap2, ap);
1189 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1190 buf = (char *) pwmd_malloc (len);
1191 if (!buf)
1193 va_end (ap2);
1194 return FINISH (GPG_ERR_ENOMEM);
1197 len = vsnprintf (buf, len, cmd, ap2);
1198 va_end (ap2);
1200 if (buf[strlen (buf) - 1] == '\n')
1201 buf[strlen (buf) - 1] = 0;
1202 if (buf[strlen (buf) - 1] == '\r')
1203 buf[strlen (buf) - 1] = 0;
1205 pwm->inquire_func = func;
1206 pwm->inquire_data = user;
1207 pwm->inquire_sent = 0;
1208 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1209 pwmd_free (buf);
1210 return rc;
1213 gpg_error_t
1214 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1215 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1217 va_list ap;
1219 if (result)
1220 *result = NULL;
1222 if (len)
1223 *len = 0;
1225 if (!pwm || !cmd)
1226 return FINISH (GPG_ERR_INV_ARG);
1227 if (!pwm->ctx)
1228 return FINISH (GPG_ERR_INV_STATE);
1230 va_start (ap, cmd);
1231 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1232 va_end (ap);
1233 return rc;
1236 static gpg_error_t
1237 send_pinentry_timeout (pwm_t *pwm)
1239 gpg_error_t rc = 0;
1241 if ((pwm->pinentry_timeout >= 0
1242 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1243 || (pwm->pinentry_timeout == -1
1244 && pwm->pinentry_timeout != pwm->current_pinentry_timeout))
1246 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1247 "OPTION pinentry-timeout=%i",
1248 pwm->pinentry_timeout);
1249 if (!rc)
1250 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1253 return rc;
1256 static gpg_error_t
1257 send_pinentry_options (pwm_t * pwm)
1259 gpg_error_t rc;
1261 // Pwmd >= 3.1 uses gpgme to do the pinentry settings.
1262 if (pwm->version && pwm->version >= 0x030100)
1263 return 0;
1265 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1266 "OPTION disable-pinentry=0");
1267 if (!rc && pwm->pinentry_tty)
1268 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1269 pwm->pinentry_tty);
1271 if (!rc && pwm->pinentry_term)
1272 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1273 pwm->pinentry_term);
1275 if (!rc && pwm->pinentry_display)
1276 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1277 pwm->pinentry_display);
1279 if (!rc && pwm->pinentry_desc)
1280 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1281 pwm->pinentry_desc);
1283 if (!rc && pwm->pinentry_lcctype)
1284 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1285 pwm->pinentry_lcctype);
1287 if (!rc && pwm->pinentry_lcmessages)
1288 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1289 pwm->pinentry_lcmessages);
1291 if (!rc)
1292 rc = send_pinentry_timeout (pwm);
1294 return rc;
1297 gpg_error_t
1298 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1300 if (!pwm || !result)
1301 return FINISH (GPG_ERR_INV_ARG);
1303 *result = PWMD_SOCKET_LOCAL;
1305 if (pwm->fd == -1)
1306 return FINISH (GPG_ERR_INV_STATE);
1308 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1309 #ifdef WITH_SSH
1310 if (pwm->tcp && pwm->tcp->ssh)
1311 *result = PWMD_SOCKET_SSH;
1312 #endif
1313 #ifdef WITH_GNUTLS
1314 if (pwm->tcp && pwm->tcp->tls)
1315 *result = PWMD_SOCKET_TLS;
1316 #endif
1317 #endif
1318 return 0;
1321 static gpg_error_t
1322 disable_pinentry (pwm_t *pwm, int *disable)
1324 gpg_error_t rc;
1325 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1326 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1327 #else
1328 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1329 #endif
1331 if (disable)
1332 *disable = no_pinentry;
1334 if (pwm->pinentry_disabled && no_pinentry)
1335 return 0;
1336 else if (!pwm->pinentry_disabled && !no_pinentry)
1337 return 0;
1339 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1340 no_pinentry);
1341 if (!rc)
1342 pwm->pinentry_disabled = no_pinentry;
1344 return rc;
1347 gpg_error_t
1348 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1349 void *data)
1351 gpg_error_t rc = 0;
1352 int no_pinentry = 0;
1354 if (!pwm || !filename || !*filename)
1355 return FINISH (GPG_ERR_INV_ARG);
1357 if (!pwm->ctx)
1358 return FINISH (GPG_ERR_INV_STATE);
1360 command_start (pwm);
1361 rc = disable_pinentry (pwm, &no_pinentry);
1362 if (!rc && !no_pinentry)
1363 rc = send_pinentry_options (pwm);
1365 if (!rc)
1367 pwm->pinentry_try = 0;
1368 pwmd_free (pwm->filename);
1369 pwm->filename = pwmd_strdup (filename);
1373 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1374 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1375 filename);
1377 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1378 && pwm->pinentry_disabled
1379 && ++pwm->pinentry_try < pwm->pinentry_tries);
1381 pwm->pinentry_try = 0;
1383 if (rc)
1385 pwmd_free (pwm->filename);
1386 pwm->filename = NULL;
1390 return FINISH (rc);
1393 static gpg_error_t
1394 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1395 void *data, int save)
1397 gpg_error_t rc = 0;
1399 if (!pwm)
1400 return FINISH (GPG_ERR_INV_ARG);
1401 if (!pwm->ctx)
1402 return FINISH (GPG_ERR_INV_STATE);
1404 command_start (pwm);
1405 rc = disable_pinentry (pwm, NULL);
1406 if (!rc)
1407 rc = pwmd_command (pwm, NULL, NULL, cb, data,
1408 save ? "SAVE %s" : "PASSWD %s", args ? args : "");
1410 return FINISH (rc);
1413 gpg_error_t
1414 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1416 return do_pwmd_save_passwd (pwm, args, cb, data, 0);
1419 gpg_error_t
1420 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1422 return do_pwmd_save_passwd (pwm, args, cb, data, 1);
1425 static gpg_error_t
1426 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1428 int n, *intp;
1429 size_t *sizetp;
1430 char *arg1, **charpp;
1431 gpg_error_t rc = 0;
1433 if (!pwm)
1434 return GPG_ERR_INV_ARG;
1436 command_start (pwm);
1437 switch (opt)
1439 case PWMD_OPTION_SERVER_VERSION:
1440 if (!get)
1441 return GPG_ERR_NOT_SUPPORTED;
1443 if (!pwm)
1444 rc = GPG_ERR_INV_ARG;
1445 else if (!pwm->ctx)
1446 rc = GPG_ERR_INV_STATE;
1447 else
1449 unsigned *u = va_arg (ap, unsigned *);
1450 *u = pwm->version;
1453 break;
1454 case PWMD_OPTION_SIGPIPE:
1455 if (get)
1457 intp = va_arg (ap, int *);
1458 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1459 break;
1462 n = va_arg (ap, int);
1463 if (n < 0 || n > 1)
1464 rc = GPG_ERR_INV_VALUE;
1466 if (n)
1467 pwm->opts |= OPT_SIGPIPE;
1468 else
1469 pwm->opts &= ~OPT_SIGPIPE;
1471 break;
1472 case PWMD_OPTION_LOCK_ON_OPEN:
1473 if (get)
1475 intp = va_arg (ap, int *);
1476 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1477 break;
1480 n = va_arg (ap, int);
1482 if (n < 0 || n > 1)
1483 rc = GPG_ERR_INV_VALUE;
1485 if (n)
1486 pwm->opts |= OPT_LOCK_ON_OPEN;
1487 else
1488 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1490 break;
1491 case PWMD_OPTION_INQUIRE_TOTAL:
1492 if (get)
1494 sizetp = va_arg (ap, size_t *);
1495 *sizetp = pwm->inquire_total;
1496 break;
1499 pwm->inquire_total = va_arg (ap, size_t);
1500 break;
1501 case PWMD_OPTION_STATUS_CB:
1502 if (get)
1504 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1506 *cb = pwm->status_func;
1507 break;
1510 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1511 break;
1512 case PWMD_OPTION_STATUS_DATA:
1513 if (get)
1515 void **data = va_arg (ap, void **);
1517 *data = pwm->status_data;
1518 break;
1521 pwm->status_data = va_arg (ap, void *);
1522 break;
1523 case PWMD_OPTION_NO_PINENTRY:
1524 if (get)
1526 intp = va_arg (ap, int *);
1527 *intp = pwm->disable_pinentry;
1528 break;
1531 n = va_arg (ap, int);
1533 if (n < 0 || n > 1)
1534 rc = GPG_ERR_INV_VALUE;
1535 else
1536 pwm->disable_pinentry = n;
1537 break;
1538 case PWMD_OPTION_LOCAL_PINENTRY:
1539 if (get)
1541 intp = va_arg (ap, int *);
1542 *intp = pwm->local_pinentry;
1543 break;
1546 n = va_arg (ap, int);
1548 if (n < 0 || n > 1)
1549 rc = GPG_ERR_INV_VALUE;
1550 else
1551 pwm->local_pinentry = n;
1553 break;
1554 case PWMD_OPTION_PINENTRY_TIMEOUT:
1555 if (get)
1557 intp = va_arg (ap, int *);
1558 *intp = pwm->pinentry_timeout;
1559 break;
1562 n = va_arg (ap, int);
1564 if (n < 0)
1565 rc = GPG_ERR_INV_VALUE;
1566 else
1567 pwm->pinentry_timeout = n;
1568 break;
1569 case PWMD_OPTION_PINENTRY_TRIES:
1570 if (get)
1572 intp = va_arg (ap, int *);
1573 *intp = pwm->pinentry_tries;
1574 break;
1577 n = va_arg (ap, int);
1578 pwm->pinentry_tries = n;
1579 break;
1580 case PWMD_OPTION_PINENTRY_PATH:
1581 if (get)
1583 charpp = va_arg (ap, char **);
1584 *charpp = pwm->pinentry_path;
1585 break;
1588 arg1 = va_arg (ap, char *);
1589 pwmd_free (pwm->pinentry_path);
1590 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1591 break;
1592 case PWMD_OPTION_PINENTRY_TTY:
1593 if (get)
1595 charpp = va_arg (ap, char **);
1596 *charpp = pwm->pinentry_tty;
1597 break;
1600 arg1 = va_arg (ap, char *);
1601 pwmd_free (pwm->pinentry_tty);
1602 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1603 break;
1604 case PWMD_OPTION_PINENTRY_DISPLAY:
1605 if (get)
1607 charpp = va_arg (ap, char **);
1608 *charpp = pwm->pinentry_display;
1609 break;
1612 arg1 = va_arg (ap, char *);
1613 pwmd_free (pwm->pinentry_display);
1614 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1615 break;
1616 case PWMD_OPTION_PINENTRY_TERM:
1617 if (get)
1619 charpp = va_arg (ap, char **);
1620 *charpp = pwm->pinentry_term;
1621 break;
1624 arg1 = va_arg (ap, char *);
1625 pwmd_free (pwm->pinentry_term);
1626 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1627 break;
1628 case PWMD_OPTION_PINENTRY_ERROR:
1629 if (get)
1631 charpp = va_arg (ap, char **);
1632 *charpp = pwm->pinentry_error;
1633 break;
1636 arg1 = va_arg (ap, char *);
1637 pwmd_free (pwm->pinentry_error);
1638 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1639 break;
1640 case PWMD_OPTION_PINENTRY_PROMPT:
1641 if (get)
1643 charpp = va_arg (ap, char **);
1644 *charpp = pwm->pinentry_prompt;
1645 break;
1648 arg1 = va_arg (ap, char *);
1649 pwmd_free (pwm->pinentry_prompt);
1650 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1651 break;
1652 case PWMD_OPTION_PINENTRY_DESC:
1653 if (get)
1655 charpp = va_arg (ap, char **);
1656 *charpp = pwm->pinentry_desc;
1657 break;
1660 arg1 = va_arg (ap, char *);
1661 pwmd_free (pwm->pinentry_desc);
1662 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1663 break;
1664 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1665 if (get)
1667 charpp = va_arg (ap, char **);
1668 *charpp = pwm->pinentry_lcctype;
1669 break;
1672 arg1 = va_arg (ap, char *);
1673 pwmd_free (pwm->pinentry_lcctype);
1674 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1675 break;
1676 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1677 if (get)
1679 charpp = va_arg (ap, char **);
1680 *charpp = pwm->pinentry_lcmessages;
1681 break;
1684 arg1 = va_arg (ap, char *);
1685 pwmd_free (pwm->pinentry_lcmessages);
1686 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1687 break;
1688 case PWMD_OPTION_KNOWNHOST_CB:
1689 if (get)
1691 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
1693 *cb = pwm->kh_cb;
1694 break;
1697 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1698 break;
1699 case PWMD_OPTION_KNOWNHOST_DATA:
1700 if (get)
1702 void **data = va_arg (ap, void **);
1704 *data = pwm->kh_data;
1705 break;
1708 pwm->kh_data = va_arg (ap, void *);
1709 break;
1710 case PWMD_OPTION_SSH_AGENT:
1711 if (get)
1713 intp = va_arg (ap, int *);
1714 *intp = pwm->use_agent;
1715 break;
1718 pwm->use_agent = va_arg (ap, int);
1720 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1722 pwm->use_agent = 0;
1723 rc = GPG_ERR_INV_VALUE;
1725 break;
1726 case PWMD_OPTION_TLS_VERIFY:
1727 if (get)
1729 intp = va_arg (ap, int *);
1730 *intp = pwm->tls_verify;
1731 break;
1734 pwm->tls_verify = va_arg (ap, int);
1736 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1738 pwm->tls_verify = 0;
1739 rc = GPG_ERR_INV_VALUE;
1741 break;
1742 case PWMD_OPTION_SOCKET_TIMEOUT:
1743 if (get)
1745 intp = va_arg (ap, int *);
1746 *intp = pwm->socket_timeout;
1747 break;
1750 pwm->socket_timeout = va_arg (ap, int);
1751 if (pwm->socket_timeout < 0)
1753 pwm->socket_timeout = 0;
1754 rc = GPG_ERR_INV_VALUE;
1757 #ifdef WITH_SSH
1758 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1760 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1761 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1762 pwm->socket_timeout * 1000);
1764 #endif
1765 #ifdef WITH_GNUTLS
1766 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1767 pwm->tcp->tls->timeout = pwm->socket_timeout;
1768 #endif
1769 break;
1770 case PWMD_OPTION_OVERRIDE_INQUIRE:
1771 if (get)
1773 intp = va_arg (ap, int *);
1774 *intp = pwm->override_inquire;
1775 break;
1778 pwm->override_inquire = va_arg (ap, int);
1780 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1782 pwm->override_inquire = 0;
1783 rc = GPG_ERR_INV_VALUE;
1785 break;
1786 default:
1787 rc = GPG_ERR_UNKNOWN_OPTION;
1788 break;
1791 return FINISH (rc);
1794 gpg_error_t
1795 pwmd_setopt (pwm_t * pwm, pwmd_option_t opt, ...)
1797 va_list ap;
1798 gpg_error_t rc = 0;
1800 va_start (ap, opt);
1801 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
1802 va_end (ap);
1803 return FINISH (rc);
1806 gpg_error_t
1807 pwmd_getopt (pwm_t *pwm, pwmd_option_t opt, ...)
1809 va_list ap;
1810 gpg_error_t rc = 0;
1812 va_start (ap, opt);
1813 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
1814 va_end (ap);
1815 return FINISH (rc);
1818 gpg_error_t
1819 pwmd_new (const char *name, pwm_t ** pwm)
1821 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1822 gpg_error_t rc;
1824 if (!h)
1825 return FINISH (GPG_ERR_ENOMEM);
1827 if (name)
1829 h->name = pwmd_strdup (name);
1830 if (!h->name)
1832 pwmd_free (h);
1833 return FINISH (GPG_ERR_ENOMEM);
1837 reset_handle (h);
1838 h->pinentry_timeout = -1;
1839 h->current_pinentry_timeout = -1;
1840 h->pinentry_tries = 3;
1841 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1842 h->prot = PWMD_IP_ANY;
1843 #endif
1845 if (ttyname (STDOUT_FILENO))
1847 char buf[256];
1849 ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
1850 h->pinentry_tty = pwmd_strdup (buf);
1851 if (!h->pinentry_tty)
1853 rc = GPG_ERR_ENOMEM;
1854 goto fail;
1858 if (getenv ("TERM") && h->pinentry_tty)
1860 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
1861 if (!h->pinentry_term)
1863 rc = GPG_ERR_ENOMEM;
1864 goto fail;
1868 if (getenv ("DISPLAY"))
1870 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
1871 if (!h->pinentry_display)
1873 rc = GPG_ERR_ENOMEM;
1874 goto fail;
1878 update_pinentry_settings (h);
1879 *pwm = h;
1880 return 0;
1882 fail:
1883 pwmd_close (h);
1884 return FINISH (rc);
1887 void
1888 pwmd_free (void *ptr)
1890 _xfree (ptr);
1893 void *
1894 pwmd_malloc (size_t size)
1896 return _xmalloc (size);
1899 void *
1900 pwmd_calloc (size_t nmemb, size_t size)
1902 return _xcalloc (nmemb, size);
1905 void *
1906 pwmd_realloc (void *ptr, size_t size)
1908 return _xrealloc (ptr, size);
1911 char *
1912 pwmd_strdup (const char *str)
1914 char *t;
1915 size_t len;
1916 register size_t c;
1918 len = strlen (str);
1919 t = _xmalloc ((len + 1) * sizeof (char));
1920 if (!t)
1921 return NULL;
1923 for (c = 0; c < len; c++)
1924 t[c] = str[c];
1926 t[c] = 0;
1927 return t;
1930 char *
1931 pwmd_strdup_printf (const char *fmt, ...)
1933 va_list ap, ap2;
1934 int len;
1935 char *buf;
1937 if (!fmt)
1938 return NULL;
1940 va_start (ap, fmt);
1941 va_copy (ap2, ap);
1942 len = vsnprintf (NULL, 0, fmt, ap);
1943 va_end (ap);
1944 buf = pwmd_malloc (++len);
1945 if (buf)
1946 vsnprintf (buf, len, fmt, ap2);
1948 va_end (ap2);
1949 return buf;
1952 gpg_error_t
1953 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
1954 size_t * len, pwmd_pinentry_t which)
1956 #ifndef WITH_PINENTRY
1957 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
1958 #else
1959 command_start (pwm);
1960 gpg_error_t rc = _pwmd_getpin (pwm, filename, result, len, which);
1962 return FINISH (rc);
1963 #endif
1966 const char *
1967 pwmd_version ()
1969 return LIBPWMD_VERSION_STR;
1972 unsigned int
1973 pwmd_features ()
1975 unsigned int n = 0;
1977 #ifdef WITH_PINENTRY
1978 n |= PWMD_FEATURE_PINENTRY;
1979 #endif
1980 #ifdef WITH_SSH
1981 n |= PWMD_FEATURE_SSH;
1982 #endif
1983 #ifdef WITH_QUALITY
1984 n |= PWMD_FEATURE_CRACK;
1985 #endif
1986 #ifdef WITH_GNUTLS
1987 n |= PWMD_FEATURE_GNUTLS;
1988 #endif
1989 return n;
1992 gpg_error_t
1993 pwmd_fd (pwm_t * pwm, int *fd)
1995 if (!pwm || !fd)
1996 return FINISH (GPG_ERR_INV_ARG);
1998 if (pwm->fd == -1)
1999 return FINISH (GPG_ERR_INV_STATE);
2001 *fd = pwm->fd;
2002 return 0;
2005 void
2006 pwmd_set_pointer (pwm_t *pwm, void *data)
2008 pwm->user_data = data;
2011 void *
2012 pwmd_get_pointer (pwm_t *pwm)
2014 return pwm->user_data;
2018 pwmd_tls_error (pwm_t *pwm)
2020 #ifndef WITH_GNUTLS
2021 return 0;
2022 #else
2023 return pwm ? pwm->tls_error : 0;
2024 #endif
2027 gpg_error_t
2028 pwmd_cancel (pwm_t *pwm)
2030 if (!pwm)
2031 return FINISH (GPG_ERR_INV_ARG);
2033 if (pwm->fd == -1)
2034 return FINISH (GPG_ERR_INV_STATE);
2036 /* Can only cancel the connection for the time being. */
2037 if (pwm->connected)
2038 return FINISH (GPG_ERR_INV_STATE);
2040 pwm->cancel = 1;
2041 return 0;