Fix timeout race condition with pwmd_process().
[libpwmd.git] / src / libpwmd.c
blobcf6131f5072dbafbca43f10462881a791d015d74
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
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 (pwm->socket_timeout)
334 fcntl (pwm->fd, F_SETFL, O_NONBLOCK);
336 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
337 pwm->tcp->addr->ai_family == AF_INET6
338 ? sizeof (struct sockaddr_in6)
339 : sizeof (struct sockaddr)) == -1)
341 int n;
342 struct timeval tv = { pwm->socket_timeout, 0 };
343 fd_set wfds;
345 rc = gpg_error_from_syserror ();
346 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
348 close (pwm->fd);
349 pwm->fd = -1;
350 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
351 return rc;
354 FD_ZERO (&wfds);
355 FD_SET (pwm->fd, &wfds);
356 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
357 rc = 0;
358 if (!n)
359 rc = gpg_error (GPG_ERR_ETIMEDOUT);
360 else if (n != -1)
362 socklen_t len = sizeof(int);
364 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
365 if (n)
366 rc = gpg_error_from_errno (n);
368 else if (n == -1)
369 rc = gpg_error_from_syserror ();
371 if (rc)
373 close (pwm->fd);
374 pwm->fd = -1;
375 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
376 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT)
377 return rc;
379 else
380 break;
382 else
383 break;
386 if (!rc && pwm->socket_timeout)
387 fcntl (pwm->fd, F_SETFL, 0);
389 return rc;
391 #endif
393 gpg_error_t
394 pwmd_connect (pwm_t * pwm, const char *url, ...)
396 const char *p = url;
397 gpg_error_t rc;
399 if (!pwm)
400 return FINISH (GPG_ERR_INV_ARG);
401 else if (!pwm->ctx)
403 rc = init_handle (pwm);
404 if (rc)
405 return rc;
408 if (!(pwm->opts & OPT_SIGPIPE))
409 signal (SIGPIPE, SIG_IGN);
411 #ifdef WITH_GNUTLS
412 pwm->tls_error = 0;
413 #endif
414 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
416 if (p && *p == '/')
417 rc = connect_uds (pwm, p);
418 else if (!p || !strncmp (p, "file://", 7))
420 if (p)
421 p += 7;
422 #ifdef DEFAULT_PWMD_SOCKET
423 else
424 p = DEFAULT_PWMD_SOCKET;
425 #endif
426 rc = connect_uds (pwm, p);
428 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
429 !strncmp (p, "ssh4://", 7))
431 #ifndef WITH_SSH
432 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
433 #else
434 char *host = NULL;
435 int port;
436 char *username = NULL;
438 if (!strncmp (p, "ssh6://", 7))
440 pwm->prot = PWMD_IPV6;
441 p += 7;
443 else if (!strncmp (p, "ssh4://", 7))
445 pwm->prot = PWMD_IPV4;
446 p += 7;
448 else
450 pwm->prot = PWMD_IP_ANY;
451 p += 6;
454 rc = _parse_ssh_url (p, &host, &port, &username);
455 if (!rc)
457 va_list ap;
458 char *identity = NULL;
459 char *knownhosts = NULL;
461 va_start (ap, url);
462 identity = va_arg (ap, char *);
464 if (!identity && !pwm->use_agent)
465 rc = GPG_ERR_INV_ARG;
466 else
467 knownhosts = va_arg (ap, char *);
469 va_end (ap);
471 if (!rc)
472 rc = _do_ssh_connect (pwm, host, port, identity, username,
473 knownhosts);
474 if (!rc)
476 rc = _connect_finalize (pwm);
477 if (rc)
478 free_tcp (pwm);
482 pwmd_free (host);
483 pwmd_free (username);
484 pwm->local_pinentry = 1;
485 return FINISH (rc);
486 #endif
488 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
489 !strncmp (p, "tls4://", 7))
491 #ifndef WITH_GNUTLS
492 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
493 #else
494 char *host = NULL;
495 int port;
497 if (!strncmp (p, "tls6://", 7))
499 pwm->prot = PWMD_IPV6;
500 p += 7;
502 else if (!strncmp (p, "tls4://", 7))
504 pwm->prot = PWMD_IPV4;
505 p += 7;
507 else
509 pwm->prot = PWMD_IP_ANY;
510 p += 6;
513 rc = _parse_tls_url (p, &host, &port);
514 if (!rc)
516 va_list ap;
517 char *clientcert = NULL;
518 char *clientkey = NULL;
519 char *cacert = NULL;
520 char *prio = NULL;
521 char *server_fp = NULL;
523 va_start (ap, url);
524 clientcert = va_arg (ap, char *);
526 if (!clientcert)
527 rc = GPG_ERR_INV_ARG;
528 else
530 clientkey = va_arg (ap, char *);
531 if (!clientkey)
532 rc = GPG_ERR_INV_ARG;
533 else
535 cacert = va_arg (ap, char *);
536 if (!cacert)
537 rc = GPG_ERR_INV_ARG;
538 else
540 prio = va_arg (ap, char *);
541 server_fp = va_arg (ap, char *);
546 va_end (ap);
548 if (!rc)
549 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
550 cacert, prio, server_fp, pwm->tls_verify);
551 if (!rc)
553 rc = _connect_finalize (pwm);
554 if (rc)
555 free_tcp (pwm);
559 pwmd_free (host);
560 pwm->local_pinentry = 1;
561 return FINISH (rc);
562 #endif
565 return FINISH (rc);
568 static void
569 disconnect (pwm_t * pwm)
571 if (!pwm)
572 return;
574 if (pwm->ctx)
575 assuan_release (pwm->ctx);
577 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
578 free_tcp (pwm);
579 #endif
580 pwm->ctx = NULL;
581 pwm->fd = -1;
584 void
585 pwmd_close (pwm_t * pwm)
587 if (!pwm)
588 return;
590 disconnect (pwm);
591 pwmd_free (pwm->pinentry_error);
592 pwmd_free (pwm->pinentry_desc);
593 pwmd_free (pwm->pinentry_prompt);
594 pwmd_free (pwm->pinentry_tty);
595 pwmd_free (pwm->pinentry_display);
596 pwmd_free (pwm->pinentry_term);
597 pwmd_free (pwm->pinentry_lcctype);
598 pwmd_free (pwm->pinentry_lcmessages);
599 pwmd_free (pwm->filename);
600 pwmd_free (pwm->name);
601 pwmd_free (pwm->passphrase_info);
602 pwmd_free (pwm->passphrase_hint);
604 #ifdef WITH_PINENTRY
605 if (pwm->pctx)
606 _pinentry_disconnect (pwm);
607 #endif
609 pwmd_free (pwm);
612 static gpg_error_t
613 inquire_realloc_cb (void *data, const void *buffer, size_t len)
615 membuf_t *mem = (membuf_t *) data;
616 void *p;
618 if (!buffer)
619 return 0;
621 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
622 return gpg_error (GPG_ERR_ENOMEM);
624 mem->buf = p;
625 memcpy ((char *) mem->buf + mem->len, buffer, len);
626 mem->len += len;
627 return 0;
630 static gpg_error_t
631 get_password (pwm_t * pwm, char **result, size_t * len,
632 pwmd_pinentry_t w, int echo)
634 char buf[LINE_MAX] = { 0 }, *p;
635 struct termios told, tnew;
636 char *key = NULL;
638 if (result)
639 *result = NULL;
641 if (len)
642 *len = 0;
644 if (!isatty (STDIN_FILENO))
646 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
647 return GPG_ERR_ENOTTY;
650 if (!echo)
652 if (tcgetattr (STDIN_FILENO, &told) == -1)
653 return gpg_error_from_syserror ();
655 memcpy (&tnew, &told, sizeof (struct termios));
656 tnew.c_lflag &= ~(ECHO);
657 tnew.c_lflag |= ICANON | ECHONL;
659 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
661 int n = errno;
663 tcsetattr (STDIN_FILENO, TCSANOW, &told);
664 return gpg_error_from_errno (n);
668 switch (w)
670 case PWMD_PINENTRY_OPEN:
671 fprintf (stderr, N_("Password for %s: "), pwm->filename);
672 break;
673 case PWMD_PINENTRY_OPEN_FAILED:
674 fprintf (stderr, N_("Invalid password. Password for %s: "),
675 pwm->filename);
676 break;
677 case PWMD_PINENTRY_SAVE:
678 fprintf (stderr, N_("New password for %s: "), pwm->filename);
679 break;
680 case PWMD_PINENTRY_SAVE_CONFIRM:
681 fprintf (stderr, N_("Confirm password: "));
682 break;
683 default:
684 break;
687 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
689 tcsetattr (STDIN_FILENO, TCSANOW, &told);
690 return 0;
693 if (!echo)
694 tcsetattr (STDIN_FILENO, TCSANOW, &told);
696 if (feof (stdin))
698 clearerr (stdin);
699 return GPG_ERR_CANCELED;
702 /* Strip the newline character. */
703 p[strlen (p) - 1] = 0;
705 if (buf[0])
707 key = pwmd_strdup_printf ("%s", p);
708 memset (buf, 0, sizeof (buf));
709 if (!key)
710 return GPG_ERR_ENOMEM;
712 if (result)
713 *result = key;
715 if (len)
716 *len = strlen (key);
718 else
720 if (result)
721 *result = pwmd_strdup ("");
723 if (len)
724 *len = 1;
727 return 0;
730 gpg_error_t
731 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
733 gpg_error_t rc;
734 int new_password = 0;
735 char *password = NULL, *newpass = NULL;
736 int error = 0;
738 if (data)
739 *data = NULL;
741 if (size)
742 *size = 0;
744 if (!strcmp (keyword, "NEW_PASSPHRASE"))
745 new_password = 1;
747 if (!new_password && pwm->pinentry_try)
748 error = 1;
750 again:
751 if (pwm->disable_pinentry)
753 rc = get_password (pwm, &password, size,
754 new_password ? PWMD_PINENTRY_SAVE :
755 error ? PWMD_PINENTRY_OPEN_FAILED :
756 PWMD_PINENTRY_OPEN, 0);
757 if (!rc && new_password)
758 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
761 else
763 pwmd_pinentry_t which;
765 if (error)
766 which = new_password
767 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
768 else
769 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
771 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
772 if (!rc && new_password)
773 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
774 PWMD_PINENTRY_SAVE_CONFIRM);
777 if (!rc && new_password)
779 if ((!password && newpass) || (!newpass && password)
780 || (newpass && password && strcmp (newpass, password)))
782 if (pwm->disable_pinentry)
783 fprintf (stderr, N_("Passphrases do not match.\n"));
785 pwmd_free (password);
786 pwmd_free (newpass);
787 password = newpass = NULL;
788 error = 1;
789 goto again;
793 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
794 pwmd_free (newpass);
795 if (!rc && data)
796 *data = password;
798 return rc;
801 static gpg_error_t
802 inquire_cb (void *data, const char *keyword)
804 pwm_t *pwm = (pwm_t *) data;
805 gpg_error_t rc = 0;
806 int free_result = 0;
807 char *result = NULL;
808 int is_password = 0;
809 int new_password = 0;
811 if (!strcmp (keyword, "PASSPHRASE"))
812 is_password = 1;
813 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
814 new_password = 1;
816 /* Shouldn't get this far without a callback. */
817 if (!pwm->override_inquire && !pwm->inquire_func
818 && !is_password && !new_password)
819 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
821 for (;;)
823 size_t len = 0;
824 gpg_error_t arc;
826 result = NULL;
828 if (!pwm->override_inquire && (is_password || new_password))
830 free_result = 1;
831 rc = pwmd_password (data, keyword, &result, &len);
832 if (!rc)
833 rc = GPG_ERR_EOF;
835 else
836 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
837 &len);
839 cancel:
840 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
842 #ifndef LIBASSUAN_2_1_0
843 gpg_error_t trc = rc;
845 /* Cancel this inquire. */
846 rc = assuan_send_data (pwm->ctx, NULL, 1);
847 if (!rc)
849 char *line;
850 size_t len;
852 /* There is a bug (or feature?) in assuan_send_data() that
853 * when cancelling an inquire the next read from the server is
854 * not done until the next command making the next command
855 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
857 rc = assuan_read_line (pwm->ctx, &line, &len);
859 /* Restore the original error. This differs from the error
860 * returned from the pwmd command (GPG_ERR_CANCELED). This
861 * error is returned to the calling function.
863 if (!rc)
864 rc = trc;
866 #endif
867 break;
870 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
872 if (len <= 0 && !result)
874 rc = 0;
875 break;
877 else if ((len <= 0 && result) || (len && !result))
879 rc = gpg_error (GPG_ERR_INV_ARG);
880 break;
883 if (pwm->inquire_maxlen
884 && pwm->inquire_sent + len > pwm->inquire_maxlen)
886 rc = gpg_error (GPG_ERR_TOO_LARGE);
887 if (!free_result)
888 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
889 &result, &len);
890 goto cancel;
893 arc = assuan_send_data (pwm->ctx, result, len);
894 if (gpg_err_code (rc) == GPG_ERR_EOF)
896 rc = arc;
897 break;
900 rc = arc;
902 else if (rc)
903 break;
905 if (!rc)
907 pwm->inquire_sent += len;
909 if (pwm->status_func)
911 char buf[ASSUAN_LINELENGTH];
913 snprintf (buf, sizeof (buf), "XFER %lu %lu", pwm->inquire_sent,
914 pwm->inquire_total);
915 rc = pwm->status_func (pwm->status_data, buf);
916 if (rc)
917 continue;
922 if (free_result)
923 pwmd_free (result);
925 return rc;
928 static gpg_error_t
929 parse_assuan_line (pwm_t * pwm)
931 gpg_error_t rc;
932 char *line;
933 size_t len;
935 rc = assuan_read_line (pwm->ctx, &line, &len);
936 if (!rc)
938 if (line[0] == 'O' && line[1] == 'K' &&
939 (line[2] == 0 || line[2] == ' '))
942 else if (line[0] == '#')
945 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
947 if (pwm->status_func)
949 rc = pwm->status_func (pwm->status_data,
950 line[1] == 0 ? line + 1 : line + 2);
953 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
954 (line[3] == 0 || line[3] == ' '))
956 line += 4;
957 rc = strtol (line, NULL, 10);
961 return rc;
964 static void
965 reset_handle (pwm_t *pwm)
967 pwm->fd = -1;
968 pwm->pinentry_disabled = 0;
969 #ifdef WITH_PINENTRY
970 if (pwm->pctx)
971 _pinentry_disconnect (pwm);
972 #endif
973 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
974 #ifdef WITH_GNUTLS
975 pwm->tls_error = 0;
976 #endif
978 if (pwm->tcp)
979 pwm->tcp->rc = 0;
980 #endif
983 gpg_error_t
984 pwmd_disconnect (pwm_t * pwm)
986 if (!pwm)
987 return FINISH (GPG_ERR_INV_ARG);
989 if (pwm->fd == -1)
990 return FINISH (GPG_ERR_INV_STATE);
992 disconnect (pwm);
993 reset_handle (pwm);
994 return 0;
997 /* Note that this should only be called when not in a command. */
998 gpg_error_t
999 pwmd_process (pwm_t * pwm)
1001 gpg_error_t rc = 0;
1002 fd_set fds;
1003 struct timeval tv = { 0, 0 };
1004 int n;
1006 if (!pwm || pwm->fd == -1)
1007 return FINISH (GPG_ERR_INV_ARG);
1008 else if (!pwm->ctx)
1009 return FINISH (GPG_ERR_INV_STATE);
1011 FD_ZERO (&fds);
1012 FD_SET (pwm->fd, &fds);
1013 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1015 if (n == -1)
1016 return FINISH (gpg_error_from_syserror ());
1018 if (n > 0)
1020 if (FD_ISSET (pwm->fd, &fds))
1021 rc = parse_assuan_line (pwm);
1024 while (!rc && assuan_pending_line (pwm->ctx))
1025 rc = parse_assuan_line (pwm);
1027 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1028 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1030 close (pwm->fd);
1031 pwm->fd = -1;
1033 #endif
1035 return FINISH (rc);
1038 static gpg_error_t
1039 status_cb (void *data, const char *line)
1041 pwm_t *pwm = data;
1043 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1044 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1045 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1047 pwmd_free (pwm->passphrase_hint);
1048 pwm->passphrase_hint = pwmd_strdup (line+16);
1050 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1052 pwmd_free (pwm->passphrase_info);
1053 pwm->passphrase_info = pwmd_strdup (line+16);
1056 if (pwm->status_func)
1057 return pwm->status_func (pwm->status_data, line);
1059 return 0;
1062 gpg_error_t
1063 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1064 char **result, size_t * len, const char *cmd)
1066 membuf_t data;
1067 gpg_error_t rc;
1069 if (!cmd || !*cmd)
1070 return FINISH (GPG_ERR_INV_ARG);
1072 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1073 return FINISH (GPG_ERR_LINE_TOO_LONG);
1075 data.len = 0;
1076 data.buf = NULL;
1077 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1078 #ifdef WITH_QUALITY
1079 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1080 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1081 #else
1082 inquire_cb, pwm,
1083 #endif
1084 status_cb, pwm);
1086 if (rc)
1088 if (data.buf)
1090 pwmd_free (data.buf);
1091 data.buf = NULL;
1094 else
1096 if (data.buf)
1098 inquire_realloc_cb (&data, "", 1);
1100 if (result)
1101 *result = (char *) data.buf;
1102 else
1103 pwmd_free (data.buf);
1105 if (len)
1106 *len = data.len;
1110 pwm->inquire_maxlen = 0;
1111 return rc;
1114 gpg_error_t
1115 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1116 pwmd_inquire_cb_t func, void *user, const char *cmd,
1117 va_list ap)
1119 char *buf;
1120 size_t len;
1121 va_list ap2;
1123 if (result)
1124 *result = NULL;
1126 if (rlen)
1127 *rlen = 0;
1129 if (!pwm || !cmd)
1130 return FINISH (GPG_ERR_INV_ARG);
1131 if (!pwm->ctx)
1132 return FINISH (GPG_ERR_INV_STATE);
1135 * C99 allows the dst pointer to be null which will calculate the length
1136 * of the would-be result and return it.
1138 va_copy (ap2, ap);
1139 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1140 buf = (char *) pwmd_malloc (len);
1141 if (!buf)
1143 va_end (ap2);
1144 return FINISH (GPG_ERR_ENOMEM);
1147 len = vsnprintf (buf, len, cmd, ap2);
1148 va_end (ap2);
1150 if (buf[strlen (buf) - 1] == '\n')
1151 buf[strlen (buf) - 1] = 0;
1152 if (buf[strlen (buf) - 1] == '\r')
1153 buf[strlen (buf) - 1] = 0;
1155 pwm->inquire_func = func;
1156 pwm->inquire_data = user;
1157 pwm->inquire_sent = 0;
1158 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1159 pwmd_free (buf);
1160 return rc;
1163 gpg_error_t
1164 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1165 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1167 va_list ap;
1169 if (result)
1170 *result = NULL;
1172 if (len)
1173 *len = 0;
1175 if (!pwm || !cmd)
1176 return FINISH (GPG_ERR_INV_ARG);
1177 if (!pwm->ctx)
1178 return FINISH (GPG_ERR_INV_STATE);
1180 va_start (ap, cmd);
1181 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1182 va_end (ap);
1183 return rc;
1186 static gpg_error_t
1187 send_pinentry_options (pwm_t * pwm)
1189 gpg_error_t rc;
1191 // Pwmd >= 3.1 uses gpgme to do the pinentry settings.
1192 if (pwm->version && pwm->version >= 0x030100)
1193 return 0;
1195 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1196 "OPTION disable-pinentry=0");
1197 if (!rc && pwm->pinentry_tty)
1198 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1199 pwm->pinentry_tty);
1201 if (!rc && pwm->pinentry_term)
1202 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1203 pwm->pinentry_term);
1205 if (!rc && pwm->pinentry_display)
1206 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1207 pwm->pinentry_display);
1209 if (!rc && pwm->pinentry_desc)
1210 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1211 pwm->pinentry_desc);
1213 if (!rc && pwm->pinentry_lcctype)
1214 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1215 pwm->pinentry_lcctype);
1217 if (!rc && pwm->pinentry_lcmessages)
1218 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1219 pwm->pinentry_lcmessages);
1221 if (!rc && pwm->pinentry_timeout >= 0)
1222 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1223 "OPTION pinentry-timeout=%i", pwm->pinentry_timeout);
1225 return rc;
1228 gpg_error_t
1229 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1231 if (!pwm || !result)
1232 return FINISH (GPG_ERR_INV_ARG);
1234 *result = PWMD_SOCKET_LOCAL;
1236 if (pwm->fd == -1)
1237 return FINISH (GPG_ERR_INV_STATE);
1239 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1240 #ifdef WITH_SSH
1241 if (pwm->tcp && pwm->tcp->ssh)
1242 *result = PWMD_SOCKET_SSH;
1243 #endif
1244 #ifdef WITH_GNUTLS
1245 if (pwm->tcp && pwm->tcp->tls)
1246 *result = PWMD_SOCKET_TLS;
1247 #endif
1248 #endif
1249 return 0;
1252 static gpg_error_t
1253 disable_pinentry (pwm_t *pwm, int *disable)
1255 gpg_error_t rc;
1256 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1257 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1258 #else
1259 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1260 #endif
1262 if (disable)
1263 *disable = no_pinentry;
1265 if (pwm->pinentry_disabled && no_pinentry)
1266 return 0;
1267 else if (!pwm->pinentry_disabled && !no_pinentry)
1268 return 0;
1270 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1271 no_pinentry);
1272 if (!rc)
1273 pwm->pinentry_disabled = no_pinentry;
1275 return rc;
1278 gpg_error_t
1279 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1280 void *data)
1282 gpg_error_t rc = 0;
1283 int no_pinentry = 0;
1285 if (!pwm || !filename || !*filename)
1286 return FINISH (GPG_ERR_INV_ARG);
1288 if (!pwm->ctx)
1289 return FINISH (GPG_ERR_INV_STATE);
1291 rc = disable_pinentry (pwm, &no_pinentry);
1292 if (!rc && !no_pinentry)
1293 rc = send_pinentry_options (pwm);
1295 if (!rc)
1297 pwm->pinentry_try = 0;
1298 pwmd_free (pwm->filename);
1299 pwm->filename = pwmd_strdup (filename);
1303 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1304 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1305 filename);
1307 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1308 && pwm->pinentry_disabled
1309 && ++pwm->pinentry_try < pwm->pinentry_tries);
1311 pwm->pinentry_try = 0;
1313 if (rc)
1315 pwmd_free (pwm->filename);
1316 pwm->filename = NULL;
1320 return FINISH (rc);
1323 static gpg_error_t
1324 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1325 void *data, int save)
1327 gpg_error_t rc = 0;
1329 if (!pwm)
1330 return FINISH (GPG_ERR_INV_ARG);
1331 if (!pwm->ctx)
1332 return FINISH (GPG_ERR_INV_STATE);
1334 rc = disable_pinentry (pwm, NULL);
1335 if (!rc)
1336 rc = pwmd_command (pwm, NULL, NULL, cb, data,
1337 save ? "SAVE %s" : "PASSWD %s", args ? args : "");
1339 return FINISH (rc);
1342 gpg_error_t
1343 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1345 return do_pwmd_save_passwd (pwm, args, cb, data, 0);
1348 gpg_error_t
1349 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1351 return do_pwmd_save_passwd (pwm, args, cb, data, 1);
1354 static gpg_error_t
1355 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1357 int n, *intp;
1358 size_t *sizetp;
1359 char *arg1, **charpp;
1360 gpg_error_t rc = 0;
1362 if (!pwm)
1363 return GPG_ERR_INV_ARG;
1365 switch (opt)
1367 case PWMD_OPTION_SIGPIPE:
1368 if (get)
1370 intp = va_arg (ap, int *);
1371 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1372 break;
1375 n = va_arg (ap, int);
1376 if (n < 0 || n > 1)
1377 rc = GPG_ERR_INV_VALUE;
1379 if (n)
1380 pwm->opts |= OPT_SIGPIPE;
1381 else
1382 pwm->opts &= ~OPT_SIGPIPE;
1384 break;
1385 case PWMD_OPTION_LOCK_ON_OPEN:
1386 if (get)
1388 intp = va_arg (ap, int *);
1389 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1390 break;
1393 n = va_arg (ap, int);
1395 if (n < 0 || n > 1)
1396 rc = GPG_ERR_INV_VALUE;
1398 if (n)
1399 pwm->opts |= OPT_LOCK_ON_OPEN;
1400 else
1401 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1403 break;
1404 case PWMD_OPTION_INQUIRE_TOTAL:
1405 if (get)
1407 sizetp = va_arg (ap, size_t *);
1408 *sizetp = pwm->inquire_total;
1409 break;
1412 pwm->inquire_total = va_arg (ap, size_t);
1413 break;
1414 case PWMD_OPTION_STATUS_CB:
1415 if (get)
1417 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1419 *cb = pwm->status_func;
1420 break;
1423 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1424 break;
1425 case PWMD_OPTION_STATUS_DATA:
1426 if (get)
1428 void **data = va_arg (ap, void **);
1430 *data = pwm->status_data;
1431 break;
1434 pwm->status_data = va_arg (ap, void *);
1435 break;
1436 case PWMD_OPTION_NO_PINENTRY:
1437 if (get)
1439 intp = va_arg (ap, int *);
1440 *intp = pwm->disable_pinentry;
1441 break;
1444 n = va_arg (ap, int);
1446 if (n < 0 || n > 1)
1447 rc = GPG_ERR_INV_VALUE;
1448 else
1449 pwm->disable_pinentry = n;
1451 if (!rc && pwm->ctx)
1452 rc = disable_pinentry (pwm, NULL);
1453 break;
1454 case PWMD_OPTION_LOCAL_PINENTRY:
1455 if (get)
1457 intp = va_arg (ap, int *);
1458 *intp = pwm->local_pinentry;
1459 break;
1462 n = va_arg (ap, int);
1464 if (n < 0 || n > 1)
1465 rc = GPG_ERR_INV_VALUE;
1466 else
1467 pwm->local_pinentry = n;
1469 break;
1470 case PWMD_OPTION_PINENTRY_TIMEOUT:
1471 if (get)
1473 intp = va_arg (ap, int *);
1474 *intp = pwm->pinentry_timeout;
1475 break;
1478 n = va_arg (ap, int);
1480 if (n < 0)
1481 rc = GPG_ERR_INV_VALUE;
1482 else
1483 pwm->pinentry_timeout = n;
1485 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1486 if (!rc && pwm->fd != -1 && !pwm->tcp)
1487 #else
1488 if (!rc && pwm->fd != -1)
1489 #endif
1490 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1491 "OPTION pinentry-timeout=%i", pwm->pinentry_timeout);
1492 break;
1493 case PWMD_OPTION_PINENTRY_TRIES:
1494 if (get)
1496 intp = va_arg (ap, int *);
1497 *intp = pwm->pinentry_tries;
1498 break;
1501 n = va_arg (ap, int);
1502 pwm->pinentry_tries = n;
1503 break;
1504 case PWMD_OPTION_PINENTRY_PATH:
1505 if (get)
1507 charpp = va_arg (ap, char **);
1508 *charpp = pwm->pinentry_path;
1509 break;
1512 arg1 = va_arg (ap, char *);
1513 pwmd_free (pwm->pinentry_path);
1514 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1515 break;
1516 case PWMD_OPTION_PINENTRY_TTY:
1517 if (get)
1519 charpp = va_arg (ap, char **);
1520 *charpp = pwm->pinentry_tty;
1521 break;
1524 arg1 = va_arg (ap, char *);
1525 pwmd_free (pwm->pinentry_tty);
1526 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1527 break;
1528 case PWMD_OPTION_PINENTRY_DISPLAY:
1529 if (get)
1531 charpp = va_arg (ap, char **);
1532 *charpp = pwm->pinentry_display;
1533 break;
1536 arg1 = va_arg (ap, char *);
1537 pwmd_free (pwm->pinentry_display);
1538 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1539 break;
1540 case PWMD_OPTION_PINENTRY_TERM:
1541 if (get)
1543 charpp = va_arg (ap, char **);
1544 *charpp = pwm->pinentry_term;
1545 break;
1548 arg1 = va_arg (ap, char *);
1549 pwmd_free (pwm->pinentry_term);
1550 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1551 break;
1552 case PWMD_OPTION_PINENTRY_ERROR:
1553 if (get)
1555 charpp = va_arg (ap, char **);
1556 *charpp = pwm->pinentry_error;
1557 break;
1560 arg1 = va_arg (ap, char *);
1561 pwmd_free (pwm->pinentry_error);
1562 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1563 break;
1564 case PWMD_OPTION_PINENTRY_PROMPT:
1565 if (get)
1567 charpp = va_arg (ap, char **);
1568 *charpp = pwm->pinentry_prompt;
1569 break;
1572 arg1 = va_arg (ap, char *);
1573 pwmd_free (pwm->pinentry_prompt);
1574 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1575 break;
1576 case PWMD_OPTION_PINENTRY_DESC:
1577 if (get)
1579 charpp = va_arg (ap, char **);
1580 *charpp = pwm->pinentry_desc;
1581 break;
1584 arg1 = va_arg (ap, char *);
1585 pwmd_free (pwm->pinentry_desc);
1586 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1587 break;
1588 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1589 if (get)
1591 charpp = va_arg (ap, char **);
1592 *charpp = pwm->pinentry_lcctype;
1593 break;
1596 arg1 = va_arg (ap, char *);
1597 pwmd_free (pwm->pinentry_lcctype);
1598 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1599 break;
1600 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1601 if (get)
1603 charpp = va_arg (ap, char **);
1604 *charpp = pwm->pinentry_lcmessages;
1605 break;
1608 arg1 = va_arg (ap, char *);
1609 pwmd_free (pwm->pinentry_lcmessages);
1610 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1611 break;
1612 case PWMD_OPTION_KNOWNHOST_CB:
1613 if (get)
1615 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
1617 *cb = pwm->kh_cb;
1618 break;
1621 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1622 break;
1623 case PWMD_OPTION_KNOWNHOST_DATA:
1624 if (get)
1626 void **data = va_arg (ap, void **);
1628 *data = pwm->kh_data;
1629 break;
1632 pwm->kh_data = va_arg (ap, void *);
1633 break;
1634 case PWMD_OPTION_SSH_AGENT:
1635 if (get)
1637 intp = va_arg (ap, int *);
1638 *intp = pwm->use_agent;
1639 break;
1642 pwm->use_agent = va_arg (ap, int);
1644 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1646 pwm->use_agent = 0;
1647 rc = GPG_ERR_INV_VALUE;
1649 break;
1650 case PWMD_OPTION_TLS_VERIFY:
1651 if (get)
1653 intp = va_arg (ap, int *);
1654 *intp = pwm->tls_verify;
1655 break;
1658 pwm->tls_verify = va_arg (ap, int);
1660 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1662 pwm->tls_verify = 0;
1663 rc = GPG_ERR_INV_VALUE;
1665 break;
1666 case PWMD_OPTION_SOCKET_TIMEOUT:
1667 if (get)
1669 intp = va_arg (ap, int *);
1670 *intp = pwm->socket_timeout;
1671 break;
1674 pwm->socket_timeout = va_arg (ap, int);
1675 if (pwm->socket_timeout < 0)
1677 pwm->socket_timeout = 0;
1678 rc = GPG_ERR_INV_VALUE;
1681 #ifdef WITH_SSH
1682 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1684 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1685 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1686 pwm->socket_timeout * 1000);
1688 #endif
1689 #ifdef WITH_GNUTLS
1690 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1691 pwm->tcp->tls->timeout = pwm->socket_timeout;
1692 #endif
1693 break;
1694 case PWMD_OPTION_OVERRIDE_INQUIRE:
1695 if (get)
1697 intp = va_arg (ap, int *);
1698 *intp = pwm->override_inquire;
1699 break;
1702 pwm->override_inquire = va_arg (ap, int);
1704 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1706 pwm->override_inquire = 0;
1707 rc = GPG_ERR_INV_VALUE;
1709 break;
1710 default:
1711 rc = GPG_ERR_UNKNOWN_OPTION;
1712 break;
1715 return FINISH (rc);
1718 gpg_error_t
1719 pwmd_setopt (pwm_t * pwm, pwmd_option_t opt, ...)
1721 va_list ap;
1722 gpg_error_t rc = 0;
1724 va_start (ap, opt);
1725 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
1726 va_end (ap);
1727 return FINISH (rc);
1730 gpg_error_t
1731 pwmd_getopt (pwm_t *pwm, pwmd_option_t opt, ...)
1733 va_list ap;
1734 gpg_error_t rc = 0;
1736 va_start (ap, opt);
1737 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
1738 va_end (ap);
1739 return FINISH (rc);
1742 gpg_error_t
1743 pwmd_new (const char *name, pwm_t ** pwm)
1745 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1746 gpg_error_t rc;
1748 if (!h)
1749 return FINISH (GPG_ERR_ENOMEM);
1751 if (name)
1753 h->name = pwmd_strdup (name);
1754 if (!h->name)
1756 pwmd_free (h);
1757 return FINISH (GPG_ERR_ENOMEM);
1761 reset_handle (h);
1762 h->pinentry_timeout = -1;
1763 h->pinentry_tries = 3;
1764 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1765 h->prot = PWMD_IP_ANY;
1766 #endif
1768 if (ttyname (STDOUT_FILENO))
1770 char buf[256];
1772 ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
1773 h->pinentry_tty = pwmd_strdup (buf);
1774 if (!h->pinentry_tty)
1776 rc = GPG_ERR_ENOMEM;
1777 goto fail;
1781 if (getenv ("TERM") && h->pinentry_tty)
1783 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
1784 if (!h->pinentry_term)
1786 rc = GPG_ERR_ENOMEM;
1787 goto fail;
1791 if (getenv ("DISPLAY"))
1793 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
1794 if (!h->pinentry_display)
1796 rc = GPG_ERR_ENOMEM;
1797 goto fail;
1801 update_pinentry_settings (h);
1802 *pwm = h;
1803 return 0;
1805 fail:
1806 pwmd_close (h);
1807 return FINISH (rc);
1810 void
1811 pwmd_free (void *ptr)
1813 _xfree (ptr);
1816 void *
1817 pwmd_malloc (size_t size)
1819 return _xmalloc (size);
1822 void *
1823 pwmd_calloc (size_t nmemb, size_t size)
1825 return _xcalloc (nmemb, size);
1828 void *
1829 pwmd_realloc (void *ptr, size_t size)
1831 return _xrealloc (ptr, size);
1834 char *
1835 pwmd_strdup (const char *str)
1837 char *t;
1838 size_t len;
1839 register size_t c;
1841 len = strlen (str);
1842 t = _xmalloc ((len + 1) * sizeof (char));
1843 if (!t)
1844 return NULL;
1846 for (c = 0; c < len; c++)
1847 t[c] = str[c];
1849 t[c] = 0;
1850 return t;
1853 char *
1854 pwmd_strdup_printf (const char *fmt, ...)
1856 va_list ap, ap2;
1857 int len;
1858 char *buf;
1860 if (!fmt)
1861 return NULL;
1863 va_start (ap, fmt);
1864 va_copy (ap2, ap);
1865 len = vsnprintf (NULL, 0, fmt, ap);
1866 va_end (ap);
1867 buf = pwmd_malloc (++len);
1868 if (buf)
1869 vsnprintf (buf, len, fmt, ap2);
1871 va_end (ap2);
1872 return buf;
1875 gpg_error_t
1876 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
1877 size_t * len, pwmd_pinentry_t which)
1879 #ifndef WITH_PINENTRY
1880 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
1881 #else
1882 gpg_error_t rc = _pwmd_getpin (pwm, filename, result, len, which);
1884 return FINISH (rc);
1885 #endif
1888 const char *
1889 pwmd_version ()
1891 return LIBPWMD_VERSION_STR;
1894 unsigned int
1895 pwmd_features ()
1897 unsigned int n = 0;
1899 #ifdef WITH_PINENTRY
1900 n |= PWMD_FEATURE_PINENTRY;
1901 #endif
1902 #ifdef WITH_SSH
1903 n |= PWMD_FEATURE_SSH;
1904 #endif
1905 #ifdef WITH_QUALITY
1906 n |= PWMD_FEATURE_CRACK;
1907 #endif
1908 #ifdef WITH_GNUTLS
1909 n |= PWMD_FEATURE_GNUTLS;
1910 #endif
1911 return n;
1914 gpg_error_t
1915 pwmd_fd (pwm_t * pwm, int *fd)
1917 if (!pwm || !fd)
1918 return FINISH (GPG_ERR_INV_ARG);
1920 if (pwm->fd == -1)
1921 return FINISH (GPG_ERR_INV_STATE);
1923 *fd = pwm->fd;
1924 return 0;
1927 void
1928 pwmd_set_pointer (pwm_t *pwm, void *data)
1930 pwm->user_data = data;
1933 void *
1934 pwmd_get_pointer (pwm_t *pwm)
1936 return pwm->user_data;
1940 pwmd_tls_error (pwm_t *pwm)
1942 #ifndef WITH_GNUTLS
1943 return 0;
1944 #else
1945 return pwm ? pwm->tls_error : 0;
1946 #endif