Fix CLang warning about va_start() parameter.
[libpwmd.git] / src / libpwmd.c
blobc54f328c6bbab7cf1a5b82f58348fb2f100df6d9
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
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 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
64 #include <sys/types.h>
65 #include <sys/socket.h>
66 #include <netdb.h>
67 #include <netinet/in.h>
68 #endif
70 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
71 ? gpg_error(rc) : rc
73 typedef struct
75 size_t len;
76 void *buf;
77 } membuf_t;
79 ssize_t
80 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
82 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
83 pwm_t *pwm = assuan_get_pointer (ctx);
85 #ifdef WITH_SSH
86 if (pwm && pwm->tcp && pwm->tcp->ssh)
87 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
88 #endif
89 #ifdef WITH_GNUTLS
90 if (pwm && pwm->tcp && pwm->tcp->tls)
91 return read_hook_tls (pwm, fd, data, len);
92 #endif
93 #endif
95 return read ((int) fd, data, len);
98 ssize_t
99 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
100 size_t len)
102 ssize_t wrote;
103 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
104 pwm_t *pwm = assuan_get_pointer (ctx);
106 #ifdef WITH_SSH
107 if (pwm && pwm->tcp && pwm->tcp->ssh)
108 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
109 #endif
110 #ifdef WITH_GNUTLS
111 if (pwm && pwm->tcp && pwm->tcp->tls)
112 return write_hook_tls (pwm, fd, data, len);
113 #endif
114 #endif
116 /* libassuan cannot handle EAGAIN when doing writes. */
119 wrote = write ((int) fd, data, len);
120 if (wrote == -1 && errno == EAGAIN)
121 usleep (50000);
123 while (wrote == -1 && errno == EAGAIN);
125 return wrote;
128 pid_t
129 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
130 int options)
132 return waitpid (pid, status, options);
135 gpg_error_t
136 pwmd_init ()
138 static int initialized;
140 #ifdef WITH_GNUTLS
141 // May be called more than once.
142 gnutls_global_init ();
143 #endif
145 if (initialized)
146 return 0;
148 #ifdef ENABLE_NLS
149 bindtextdomain ("libpwmd", LOCALEDIR);
150 #endif
151 #ifdef WITH_SSH
152 libssh2_init (0);
153 #endif
154 gpgrt_init ();
155 gpgrt_set_alloc_func (_xrealloc_gpgrt);
156 initialized = 1;
157 return 0;
160 void
161 pwmd_deinit ()
163 #ifdef WITH_GNUTLS
164 gnutls_global_deinit ();
165 #endif
168 gpg_error_t
169 _connect_finalize (pwm_t * pwm)
171 gpg_error_t rc = 0;
172 char *result = NULL;
173 int active[2];
174 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
176 if (n <= 0)
177 return GPG_ERR_EBADFD;
179 pwm->fd = active[0];
180 #ifdef WITH_PINENTRY
181 pwm->pinentry_pid = -1;
182 #endif
184 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "GETINFO VERSION");
185 if (!rc)
187 pwm->version = strtoul (result, NULL, 16);
188 pwmd_free (result);
191 if (!rc && pwm->name)
192 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
193 pwm->name);
195 return rc;
198 static gpg_error_t
199 connect_uds (pwm_t * pwm, const char *path)
201 char *socketpath = NULL;
202 struct passwd pw;
203 char *pwbuf;
204 gpg_error_t rc;
206 if (!pwm)
207 return GPG_ERR_INV_ARG;
209 pwbuf = _getpwuid (&pw);
210 if (!pwbuf)
211 return gpg_error_from_syserror ();
213 if (!path || !*path)
214 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
215 else
216 socketpath = _expand_homedir ((char *) path, &pw);
218 pwmd_free (pwbuf);
219 if (!socketpath)
220 return GPG_ERR_ENOMEM;
222 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
223 pwmd_free (socketpath);
224 return rc ? rc : _connect_finalize (pwm);
227 static gpg_error_t
228 init_handle (pwm_t * pwm)
230 gpg_error_t rc;
231 static struct assuan_malloc_hooks mhooks = {
232 pwmd_malloc, pwmd_realloc, pwmd_free
234 static struct assuan_system_hooks shooks = {
235 ASSUAN_SYSTEM_HOOKS_VERSION,
236 __assuan_usleep,
237 __assuan_pipe,
238 __assuan_close,
239 hook_read,
240 hook_write,
241 //FIXME
242 NULL, //recvmsg
243 NULL, //sendmsg both are used for FD passing
244 __assuan_spawn,
245 hook_waitpid,
246 __assuan_socketpair,
247 __assuan_socket,
248 __assuan_connect
251 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
252 NULL);
253 if (rc)
254 return rc;
256 assuan_set_pointer (pwm->ctx, pwm);
257 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
258 return 0;
261 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
262 void
263 free_tcp (pwm_t *pwm)
265 struct tcp_s *tcp = pwm->tcp;
267 if (!tcp)
268 return;
270 #ifdef WITH_SSH
271 _free_ssh_conn (tcp->ssh);
272 #endif
273 #ifdef WITH_GNUTLS
274 tls_free (pwm);
275 #endif
277 pwmd_free (tcp->host);
278 if (tcp->addrs)
280 freeaddrinfo (tcp->addrs);
281 tcp->addrs = NULL;
284 pthread_cond_destroy (&tcp->dns_cond);
285 pthread_mutex_destroy (&tcp->dns_mutex);
286 pwmd_free (tcp);
287 pwm->tcp = NULL;
289 #endif
291 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
292 static void *
293 resolve_host_thread (void *arg)
295 pwm_t *pwm = arg;
296 struct addrinfo hints = { 0 };
297 char portstr[6];
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 int *n = pwmd_malloc (sizeof (int));
315 pthread_cleanup_push (pwmd_free, n);
316 *n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
317 pthread_cleanup_pop (0);
318 pthread_cond_broadcast (&pwm->tcp->dns_cond);
319 pthread_exit (n);
320 return NULL;
323 gpg_error_t
324 tcp_connect_common (pwm_t * pwm)
326 #define TS_TIMEOUT 50000000L
327 int n;
328 gpg_error_t rc = 0;
329 pthread_t tid;
330 time_t now;
332 time (&now);
333 n = pthread_create (&tid, NULL, resolve_host_thread, pwm);
334 if (n)
335 return gpg_error_from_errno (n);
337 pthread_mutex_lock (&pwm->tcp->dns_mutex);
339 for (;;)
341 struct timespec ts;
342 int *result = NULL;
344 clock_gettime (CLOCK_REALTIME, &ts);
345 if (ts.tv_nsec + TS_TIMEOUT >= 1000000000LL) {
346 ts.tv_sec++;
347 ts.tv_nsec = 0;
349 else
350 ts.tv_nsec += TS_TIMEOUT;
352 if (pwm->cancel)
354 #ifdef HAVE_PTHREAD_CANCEL
355 pthread_cancel (tid);
356 pthread_join (tid, NULL);
357 #else
358 pthread_join (tid, (void **)&result);
359 pwmd_free (result);
360 #endif
361 return GPG_ERR_CANCELED;
364 n = pthread_cond_timedwait (&pwm->tcp->dns_cond, &pwm->tcp->dns_mutex,
365 &ts);
366 if (n == ETIMEDOUT)
368 if (pwm->socket_timeout && ts.tv_sec - now >= pwm->socket_timeout)
370 #ifdef HAVE_PTHREAD_CANCEL
371 pthread_cancel (tid);
372 pthread_join (tid, NULL);
373 #else
374 pthread_join (tid, (void **)&result);
375 pwmd_free (result);
376 #endif
377 return GPG_ERR_ETIMEDOUT;
380 continue;
382 else if (n)
384 #ifdef HAVE_PTHREAD_CANCEL
385 pthread_cancel (tid);
386 pthread_join (tid, NULL);
387 #else
388 pthread_join (tid, (void **)&result);
389 pwmd_free (result);
390 #endif
391 return gpg_error_from_errno (n);
394 pthread_join (tid, (void **)&result);
395 n = *result;
396 pwmd_free (result);
397 break;
400 if (n)
401 return GPG_ERR_UNKNOWN_HOST; //FIXME
403 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
404 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
406 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
407 if (pwm->fd == -1)
409 rc = gpg_error_from_syserror ();
410 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
411 break;
412 continue;
415 if (fcntl (pwm->fd, F_SETFL, O_NONBLOCK) == -1)
417 rc = gpg_error_from_syserror ();
418 break;
421 if (connect (pwm->fd, pwm->tcp->addr->ai_addr,
422 pwm->tcp->addr->ai_family == AF_INET6
423 ? sizeof (struct sockaddr_in6)
424 : sizeof (struct sockaddr)) == -1)
426 int n;
427 struct timeval tv;
428 fd_set wfds;
429 unsigned elapsed = 0;
431 rc = gpg_error_from_syserror ();
432 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
434 close (pwm->fd);
435 pwm->fd = -1;
436 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
437 return rc;
438 continue;
441 again:
442 tv.tv_sec = 1;
443 tv.tv_usec = 0;
444 FD_ZERO (&wfds);
445 FD_SET (pwm->fd, &wfds);
446 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
447 rc = 0;
448 if (!n || pwm->cancel)
450 if (pwm->cancel)
451 rc = gpg_error (GPG_ERR_CANCELED);
452 else if (++elapsed >= pwm->socket_timeout)
453 rc = gpg_error (GPG_ERR_ETIMEDOUT);
454 else
455 goto again;
457 else if (n != -1)
459 socklen_t len = sizeof(int);
461 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
462 if (n)
463 rc = gpg_error_from_errno (n);
465 else if (n == -1)
466 rc = gpg_error_from_syserror ();
468 if (rc)
470 close (pwm->fd);
471 pwm->fd = -1;
472 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
473 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
474 || pwm->cancel)
475 return rc;
477 else
478 break;
480 else
481 break;
484 if (!rc)
485 if (fcntl (pwm->fd, F_SETFL, 0) == -1)
486 rc = gpg_error_from_syserror ();
488 return rc;
490 #endif
492 static void
493 command_start (pwm_t *pwm)
495 pwm->cancel = 0;
498 gpg_error_t
499 pwmd_connect (pwm_t * pwm, const char *url, ...)
501 const char *p = url;
502 gpg_error_t rc;
504 if (!pwm)
505 return FINISH (GPG_ERR_INV_ARG);
506 else if (!pwm->ctx)
508 rc = init_handle (pwm);
509 if (rc)
510 return rc;
513 command_start (pwm);
515 if (!(pwm->opts & OPT_SIGPIPE))
516 signal (SIGPIPE, SIG_IGN);
518 #ifdef WITH_GNUTLS
519 pwm->tls_error = 0;
520 #endif
521 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
523 if (p && (*p == '/' || *p == '~'))
524 rc = connect_uds (pwm, p);
525 else if (!p || !strncmp (p, "file://", 7))
527 if (p)
528 p += 7;
529 #ifdef DEFAULT_PWMD_SOCKET
530 else
531 p = DEFAULT_PWMD_SOCKET;
532 #endif
533 rc = connect_uds (pwm, p);
535 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
536 !strncmp (p, "ssh4://", 7))
538 #ifndef WITH_SSH
539 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
540 #else
541 char *host = NULL;
542 int port;
543 char *username = NULL;
545 if (!strncmp (p, "ssh6://", 7))
547 pwm->prot = PWMD_IPV6;
548 p += 7;
550 else if (!strncmp (p, "ssh4://", 7))
552 pwm->prot = PWMD_IPV4;
553 p += 7;
555 else
557 pwm->prot = PWMD_IP_ANY;
558 p += 6;
561 rc = _parse_ssh_url (p, &host, &port, &username);
562 if (!rc)
564 va_list ap;
565 char *identity = NULL;
566 char *knownhosts = NULL;
568 va_start (ap, url);
569 identity = va_arg (ap, char *);
571 if (!identity && !pwm->use_agent)
572 rc = GPG_ERR_INV_ARG;
573 else
574 knownhosts = va_arg (ap, char *);
576 va_end (ap);
578 if (!rc)
579 rc = _do_ssh_connect (pwm, host, port, identity, username,
580 knownhosts);
581 if (!rc)
583 rc = _connect_finalize (pwm);
584 if (rc)
585 free_tcp (pwm);
589 pwmd_free (host);
590 pwmd_free (username);
591 pwm->local_pinentry = 1;
592 #endif
594 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
595 !strncmp (p, "tls4://", 7))
597 #ifndef WITH_GNUTLS
598 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
599 #else
600 char *host = NULL;
601 int port;
603 if (!strncmp (p, "tls6://", 7))
605 pwm->prot = PWMD_IPV6;
606 p += 7;
608 else if (!strncmp (p, "tls4://", 7))
610 pwm->prot = PWMD_IPV4;
611 p += 7;
613 else
615 pwm->prot = PWMD_IP_ANY;
616 p += 6;
619 rc = _parse_tls_url (p, &host, &port);
620 if (!rc)
622 va_list ap;
623 char *clientcert = NULL;
624 char *clientkey = NULL;
625 char *cacert = NULL;
626 char *prio = NULL;
627 char *server_fp = NULL;
629 va_start (ap, url);
630 clientcert = va_arg (ap, char *);
632 if (!clientcert)
633 rc = GPG_ERR_INV_ARG;
634 else
636 clientkey = va_arg (ap, char *);
637 if (!clientkey)
638 rc = GPG_ERR_INV_ARG;
639 else
641 cacert = va_arg (ap, char *);
642 if (!cacert)
643 rc = GPG_ERR_INV_ARG;
644 else
646 prio = va_arg (ap, char *);
647 server_fp = va_arg (ap, char *);
652 va_end (ap);
654 if (!rc)
655 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
656 cacert, prio, server_fp, pwm->tls_verify);
657 if (!rc)
659 rc = _connect_finalize (pwm);
660 if (rc)
661 free_tcp (pwm);
665 pwmd_free (host);
666 pwm->local_pinentry = 1;
667 #endif
670 if (!rc)
671 pwm->connected = 1;
673 return FINISH (rc);
676 static void
677 disconnect (pwm_t * pwm)
679 if (!pwm)
680 return;
682 if (pwm->ctx)
683 assuan_release (pwm->ctx);
685 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
686 free_tcp (pwm);
687 #endif
688 pwm->ctx = NULL;
689 pwm->fd = -1;
690 pwm->connected = 0;
693 void
694 pwmd_close (pwm_t * pwm)
696 if (!pwm)
697 return;
699 disconnect (pwm);
700 pwmd_free (pwm->pinentry_error);
701 pwmd_free (pwm->pinentry_desc);
702 pwmd_free (pwm->pinentry_prompt);
703 pwmd_free (pwm->pinentry_tty);
704 pwmd_free (pwm->pinentry_display);
705 pwmd_free (pwm->pinentry_term);
706 pwmd_free (pwm->pinentry_lcctype);
707 pwmd_free (pwm->pinentry_lcmessages);
708 pwmd_free (pwm->filename);
709 pwmd_free (pwm->name);
710 pwmd_free (pwm->passphrase_info);
711 pwmd_free (pwm->passphrase_hint);
713 #ifdef WITH_PINENTRY
714 if (pwm->pctx)
715 _pinentry_disconnect (pwm);
716 #endif
718 pwmd_free (pwm);
721 static gpg_error_t
722 inquire_realloc_cb (void *data, const void *buffer, size_t len)
724 membuf_t *mem = (membuf_t *) data;
725 void *p;
727 if (!buffer)
728 return 0;
730 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
731 return gpg_error (GPG_ERR_ENOMEM);
733 mem->buf = p;
734 memcpy ((char *) mem->buf + mem->len, buffer, len);
735 mem->len += len;
736 return 0;
739 static gpg_error_t
740 get_password (pwm_t * pwm, char **result, size_t * len,
741 pwmd_pinentry_t w, int echo)
743 char buf[ASSUAN_LINELENGTH+1] = { 0 }, *p;
744 struct termios told, tnew;
745 char *key = NULL;
747 if (result)
748 *result = NULL;
750 if (len)
751 *len = 0;
753 if (!isatty (STDIN_FILENO))
755 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
756 return GPG_ERR_ENOTTY;
759 if (!echo)
761 if (tcgetattr (STDIN_FILENO, &told) == -1)
762 return gpg_error_from_syserror ();
764 memcpy (&tnew, &told, sizeof (struct termios));
765 tnew.c_lflag &= ~(ECHO);
766 tnew.c_lflag |= ICANON | ECHONL;
768 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
770 int n = errno;
772 tcsetattr (STDIN_FILENO, TCSANOW, &told);
773 return gpg_error_from_errno (n);
777 if (pwm->passphrase_hint)
778 fprintf(stderr, N_("Key info: %s\n"), pwm->passphrase_hint);
780 switch (w)
782 case PWMD_PINENTRY_OPEN:
783 fprintf (stderr, N_("Passphrase for %s: "), pwm->filename);
784 break;
785 case PWMD_PINENTRY_OPEN_FAILED:
786 fprintf (stderr, N_("Invalid passphrase. Passphrase for %s: "),
787 pwm->filename);
788 break;
789 case PWMD_PINENTRY_SAVE:
790 fprintf (stderr, N_("New passphrase for %s: "), pwm->filename);
791 break;
792 case PWMD_PINENTRY_SAVE_CONFIRM:
793 fprintf (stderr, N_("Repeat passphrase: "));
794 break;
795 case PWMD_PINENTRY_CONFIRM:
796 if (pwm->pinentry_desc)
797 fprintf (stderr, "%s", pwm->pinentry_desc);
799 if (pwm->pinentry_prompt)
800 fprintf (stderr, "%s", pwm->pinentry_prompt);
801 else
802 fprintf(stderr, N_("Confirm [y/N]:"));
803 default:
804 break;
807 p = fgets (buf, sizeof (buf), stdin);
809 if (!echo)
810 tcsetattr (STDIN_FILENO, TCSANOW, &told);
812 if (!p || feof (stdin))
814 clearerr (stdin);
815 return GPG_ERR_CANCELED;
818 /* Strip the newline character. */
819 p[strlen (p) - 1] = 0;
821 if (buf[0])
823 if (w == PWMD_PINENTRY_CONFIRM)
825 if (*p != 'y' && *p != 'Y')
826 return GPG_ERR_CANCELED;
827 return 0;
830 key = pwmd_strdup_printf ("%s", p);
831 wipememory (buf, 0, sizeof (buf));
832 if (!key)
833 return GPG_ERR_ENOMEM;
835 if (result)
836 *result = key;
838 if (len)
839 *len = strlen (key);
841 else
843 if (w == PWMD_PINENTRY_CONFIRM)
844 return GPG_ERR_CANCELED;
846 /* To satisfy inquire_cb(). */
847 if (result)
848 *result = pwmd_strdup ("");
850 if (len)
851 *len = 1;
854 return 0;
857 gpg_error_t
858 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
860 gpg_error_t rc;
861 int new_password = 0;
862 char *password = NULL, *newpass = NULL;
863 int error = 0;
865 command_start (pwm);
867 if (data)
868 *data = NULL;
870 if (size)
871 *size = 0;
873 if (!strcmp (keyword, "NEW_PASSPHRASE"))
874 new_password = 1;
876 if (!new_password && pwm->pinentry_try)
877 error = 1;
879 again:
880 if (pwm->disable_pinentry)
882 rc = get_password (pwm, &password, size,
883 new_password ? PWMD_PINENTRY_SAVE :
884 error ? PWMD_PINENTRY_OPEN_FAILED :
885 PWMD_PINENTRY_OPEN, 0);
886 if (!rc && new_password)
887 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
890 else
892 pwmd_pinentry_t which;
894 if (error)
895 which = new_password
896 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
897 else
898 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
900 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
901 if (!rc && new_password)
902 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
903 PWMD_PINENTRY_SAVE_CONFIRM);
906 if (!rc && new_password)
908 if ((!password && newpass) || (!newpass && password)
909 || (newpass && password && strcmp (newpass, password)))
911 if (pwm->disable_pinentry)
912 fprintf (stderr, N_("Passphrases do not match.\n"));
914 pwmd_free (password);
915 pwmd_free (newpass);
916 password = newpass = NULL;
917 error = 1;
918 goto again;
922 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
923 pwmd_free (newpass);
924 if (!rc && data)
925 *data = password;
926 else
927 pwmd_free (password);
929 return rc;
932 static gpg_error_t
933 inquire_cb (void *data, const char *keyword)
935 pwm_t *pwm = (pwm_t *) data;
936 gpg_error_t rc = 0;
937 int free_result = 0;
938 char *result = NULL;
939 int is_password = 0;
940 int new_password = 0;
942 if (!strcmp (keyword, "PASSPHRASE") || !strcmp (keyword, "SIGN_PASSPHRASE"))
943 is_password = 1;
944 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
945 new_password = 1;
947 /* Shouldn't get this far without a callback. */
948 if (!pwm->override_inquire && !pwm->inquire_func
949 && !is_password && !new_password)
950 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
952 for (;;)
954 size_t len = 0;
955 gpg_error_t arc;
957 result = NULL;
959 if (!pwm->override_inquire && (is_password || new_password))
961 free_result = 1;
962 rc = pwmd_password (data, keyword, &result, &len);
963 if (!rc)
964 rc = GPG_ERR_EOF;
966 else
967 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
968 &len);
970 /* gpg will truncate a passphrase at the first nil byte which may be bad
971 * for generated key files. */
972 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
973 && (is_password || new_password))
975 if (len && result && *result)
977 for (size_t n = 0; n < len; n++)
979 if (result[n] == 0 && n+1 != len)
980 rc = GPG_ERR_INV_PASSPHRASE;
985 cancel:
986 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
988 #ifndef LIBASSUAN_2_1_0
989 gpg_error_t trc = rc;
991 /* Cancel this inquire. */
992 rc = assuan_send_data (pwm->ctx, NULL, 1);
993 if (!rc)
995 char *line;
996 size_t len;
998 /* There is a bug (or feature?) in assuan_send_data() that
999 * when cancelling an inquire the next read from the server is
1000 * not done until the next command making the next command
1001 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
1003 rc = assuan_read_line (pwm->ctx, &line, &len);
1005 /* Restore the original error. This differs from the error
1006 * returned from the pwmd command (GPG_ERR_CANCELED). This
1007 * error is returned to the calling function.
1009 if (!rc)
1010 rc = trc;
1012 #endif
1013 break;
1016 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
1018 if (len <= 0 && !result)
1020 rc = 0;
1021 break;
1023 else if ((len <= 0 && result) || (len && !result))
1025 rc = gpg_error (GPG_ERR_INV_ARG);
1026 break;
1029 if (pwm->inquire_maxlen
1030 && pwm->inquire_sent + len > pwm->inquire_maxlen)
1032 rc = gpg_error (GPG_ERR_TOO_LARGE);
1033 if (!free_result)
1034 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
1035 &result, &len);
1036 goto cancel;
1039 arc = assuan_send_data (pwm->ctx, result, len);
1040 if (gpg_err_code (rc) == GPG_ERR_EOF)
1042 rc = arc;
1043 break;
1046 rc = arc;
1048 else if (rc)
1049 break;
1051 if (!rc)
1053 pwm->inquire_sent += len;
1055 if (pwm->status_func)
1057 char buf[ASSUAN_LINELENGTH];
1059 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
1060 pwm->inquire_total);
1061 rc = pwm->status_func (pwm->status_data, buf);
1062 if (rc)
1063 continue;
1068 if (free_result)
1069 pwmd_free (result);
1071 pwm->inquire_maxlen = pwm->inquire_sent = 0;
1072 return rc;
1075 static gpg_error_t
1076 parse_assuan_line (pwm_t * pwm)
1078 gpg_error_t rc;
1079 char *line;
1080 size_t len;
1082 rc = assuan_read_line (pwm->ctx, &line, &len);
1083 if (!rc)
1085 if (line[0] == 'O' && line[1] == 'K' &&
1086 (line[2] == 0 || line[2] == ' '))
1089 else if (line[0] == '#')
1092 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
1094 if (pwm->status_func)
1096 rc = pwm->status_func (pwm->status_data,
1097 line[1] == 0 ? line + 1 : line + 2);
1100 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
1101 (line[3] == 0 || line[3] == ' '))
1103 line += 4;
1104 rc = strtol (line, NULL, 10);
1108 return rc;
1111 static void
1112 reset_handle (pwm_t *pwm)
1114 pwm->fd = -1;
1115 pwm->cancel = 0;
1116 pwm->pinentry_disabled = 0;
1117 #ifdef WITH_PINENTRY
1118 if (pwm->pctx)
1119 _pinentry_disconnect (pwm);
1120 #endif
1121 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1122 #ifdef WITH_GNUTLS
1123 pwm->tls_error = 0;
1124 #endif
1126 if (pwm->tcp)
1127 pwm->tcp->rc = 0;
1128 #endif
1131 gpg_error_t
1132 pwmd_disconnect (pwm_t * pwm)
1134 if (!pwm)
1135 return FINISH (GPG_ERR_INV_ARG);
1137 command_start (pwm);
1139 if (pwm->fd == -1)
1140 return FINISH (GPG_ERR_INV_STATE);
1142 disconnect (pwm);
1143 reset_handle (pwm);
1144 return 0;
1147 /* Note that this should only be called when not in a command. */
1148 gpg_error_t
1149 pwmd_process (pwm_t * pwm)
1151 gpg_error_t rc = 0;
1152 fd_set fds;
1153 struct timeval tv = { 0, 0 };
1154 int n;
1156 if (!pwm || pwm->fd == -1)
1157 return FINISH (GPG_ERR_INV_ARG);
1158 else if (!pwm->ctx)
1159 return FINISH (GPG_ERR_INV_STATE);
1161 FD_ZERO (&fds);
1162 FD_SET (pwm->fd, &fds);
1163 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1165 if (n == -1)
1166 return FINISH (gpg_error_from_syserror ());
1168 if (n > 0)
1170 if (FD_ISSET (pwm->fd, &fds))
1171 rc = parse_assuan_line (pwm);
1174 while (!rc && assuan_pending_line (pwm->ctx))
1175 rc = parse_assuan_line (pwm);
1177 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1178 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1180 close (pwm->fd);
1181 pwm->fd = -1;
1183 #endif
1185 return FINISH (rc);
1188 static gpg_error_t
1189 status_cb (void *data, const char *line)
1191 pwm_t *pwm = data;
1193 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1194 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1195 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1197 pwmd_free (pwm->passphrase_hint);
1198 pwm->passphrase_hint = pwmd_strdup (line+16);
1200 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1202 pwmd_free (pwm->passphrase_info);
1203 pwm->passphrase_info = pwmd_strdup (line+16);
1206 if (pwm->status_func)
1207 return pwm->status_func (pwm->status_data, line);
1209 return 0;
1212 gpg_error_t
1213 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1214 char **result, size_t * len, const char *cmd)
1216 membuf_t data;
1217 gpg_error_t rc;
1219 if (!cmd || !*cmd)
1220 return FINISH (GPG_ERR_INV_ARG);
1222 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1223 return FINISH (GPG_ERR_LINE_TOO_LONG);
1225 data.len = 0;
1226 data.buf = NULL;
1227 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1228 #ifdef WITH_QUALITY
1229 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1230 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1231 #else
1232 inquire_cb, pwm,
1233 #endif
1234 status_cb, pwm);
1236 if (rc)
1238 if (data.buf)
1240 pwmd_free (data.buf);
1241 data.buf = NULL;
1244 else
1246 if (data.buf)
1248 inquire_realloc_cb (&data, "", 1);
1250 if (result)
1251 *result = (char *) data.buf;
1252 else
1253 pwmd_free (data.buf);
1255 if (len)
1256 *len = data.len;
1260 pwm->inquire_maxlen = 0;
1261 return rc;
1264 gpg_error_t
1265 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1266 pwmd_inquire_cb_t func, void *user, const char *cmd,
1267 va_list ap)
1269 char *buf;
1270 size_t len;
1271 va_list ap2;
1273 command_start (pwm);
1275 if (result)
1276 *result = NULL;
1278 if (rlen)
1279 *rlen = 0;
1281 if (!pwm || !cmd)
1282 return FINISH (GPG_ERR_INV_ARG);
1283 if (!pwm->ctx)
1284 return FINISH (GPG_ERR_INV_STATE);
1287 * C99 allows the dst pointer to be null which will calculate the length
1288 * of the would-be result and return it.
1290 va_copy (ap2, ap);
1291 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1292 buf = (char *) pwmd_malloc (len);
1293 if (!buf)
1295 va_end (ap2);
1296 return FINISH (GPG_ERR_ENOMEM);
1299 len = vsnprintf (buf, len, cmd, ap2);
1300 va_end (ap2);
1302 if (buf[strlen (buf) - 1] == '\n')
1303 buf[strlen (buf) - 1] = 0;
1304 if (buf[strlen (buf) - 1] == '\r')
1305 buf[strlen (buf) - 1] = 0;
1307 pwm->inquire_func = func;
1308 pwm->inquire_data = user;
1309 pwm->inquire_sent = 0;
1310 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1311 pwmd_free (buf);
1312 return rc;
1315 gpg_error_t
1316 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1317 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1319 va_list ap;
1321 if (result)
1322 *result = NULL;
1324 if (len)
1325 *len = 0;
1327 if (!pwm || !cmd)
1328 return FINISH (GPG_ERR_INV_ARG);
1329 if (!pwm->ctx)
1330 return FINISH (GPG_ERR_INV_STATE);
1332 va_start (ap, cmd);
1333 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1334 va_end (ap);
1335 return rc;
1338 static gpg_error_t
1339 send_pinentry_timeout (pwm_t *pwm)
1341 gpg_error_t rc = 0;
1343 if ((pwm->pinentry_timeout >= 0
1344 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1345 || (pwm->pinentry_timeout == -1
1346 && pwm->pinentry_timeout != pwm->current_pinentry_timeout))
1348 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1349 "OPTION pinentry-timeout=%i",
1350 pwm->pinentry_timeout);
1351 if (!rc)
1352 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1355 return rc;
1358 static gpg_error_t
1359 send_pinentry_options (pwm_t * pwm)
1361 gpg_error_t rc;
1363 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1364 "OPTION disable-pinentry=0");
1365 if (!rc && pwm->pinentry_tty)
1366 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1367 pwm->pinentry_tty);
1369 if (!rc && pwm->pinentry_term)
1370 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1371 pwm->pinentry_term);
1373 if (!rc && pwm->pinentry_display)
1374 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1375 pwm->pinentry_display);
1377 if (!rc && pwm->pinentry_desc)
1378 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1379 pwm->pinentry_desc);
1381 if (!rc && pwm->pinentry_lcctype)
1382 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1383 pwm->pinentry_lcctype);
1385 if (!rc && pwm->pinentry_lcmessages)
1386 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1387 pwm->pinentry_lcmessages);
1389 if (!rc)
1390 rc = send_pinentry_timeout (pwm);
1392 return rc;
1395 gpg_error_t
1396 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1398 if (!pwm || !result)
1399 return FINISH (GPG_ERR_INV_ARG);
1401 *result = PWMD_SOCKET_LOCAL;
1403 if (pwm->fd == -1)
1404 return FINISH (GPG_ERR_INV_STATE);
1406 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1407 #ifdef WITH_SSH
1408 if (pwm->tcp && pwm->tcp->ssh)
1409 *result = PWMD_SOCKET_SSH;
1410 #endif
1411 #ifdef WITH_GNUTLS
1412 if (pwm->tcp && pwm->tcp->tls)
1413 *result = PWMD_SOCKET_TLS;
1414 #endif
1415 #endif
1416 return 0;
1419 static gpg_error_t
1420 disable_pinentry (pwm_t *pwm, int *disable)
1422 gpg_error_t rc;
1423 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1424 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1425 #else
1426 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1427 #endif
1429 if (disable)
1430 *disable = no_pinentry;
1432 if (pwm->pinentry_disabled && no_pinentry)
1433 return 0;
1434 else if (!pwm->pinentry_disabled && !no_pinentry)
1435 return 0;
1437 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION disable-pinentry=%i",
1438 no_pinentry);
1439 if (!rc)
1440 pwm->pinentry_disabled = no_pinentry;
1442 return rc;
1445 gpg_error_t
1446 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1447 void *data)
1449 gpg_error_t rc = 0;
1450 int no_pinentry = 0;
1452 if (!pwm || !filename || !*filename)
1453 return FINISH (GPG_ERR_INV_ARG);
1455 if (!pwm->ctx)
1456 return FINISH (GPG_ERR_INV_STATE);
1458 command_start (pwm);
1459 rc = disable_pinentry (pwm, &no_pinentry);
1460 if (!rc && !no_pinentry)
1461 rc = send_pinentry_options (pwm);
1463 if (!rc)
1465 pwm->pinentry_try = 0;
1466 pwmd_free (pwm->filename);
1467 pwm->filename = pwmd_strdup (filename);
1471 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1472 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1473 filename);
1475 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1476 && pwm->pinentry_disabled
1477 && ++pwm->pinentry_try < pwm->pinentry_tries);
1479 pwm->pinentry_try = 0;
1481 if (rc)
1483 pwmd_free (pwm->filename);
1484 pwm->filename = NULL;
1488 pwmd_free (pwm->passphrase_hint);
1489 pwmd_free (pwm->passphrase_info);
1490 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1491 return FINISH (rc);
1494 static gpg_error_t
1495 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
1496 void *data, int save)
1498 gpg_error_t rc = 0;
1499 int no_pinentry = 0;
1501 if (!pwm)
1502 return FINISH (GPG_ERR_INV_ARG);
1503 if (!pwm->ctx)
1504 return FINISH (GPG_ERR_INV_STATE);
1506 command_start (pwm);
1507 rc = disable_pinentry (pwm, &no_pinentry);
1508 if (!rc && !no_pinentry)
1509 rc = send_pinentry_options (pwm);
1511 if (!rc)
1512 rc = pwmd_command (pwm, NULL, NULL, cb, data,
1513 save ? "SAVE %s" : "PASSWD %s", args ? args : "");
1515 pwmd_free (pwm->passphrase_hint);
1516 pwmd_free (pwm->passphrase_info);
1517 pwm->passphrase_info = pwm->passphrase_hint = NULL;
1518 return FINISH (rc);
1521 gpg_error_t
1522 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1524 return do_pwmd_save_passwd (pwm, args, cb, data, 0);
1527 gpg_error_t
1528 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1530 return do_pwmd_save_passwd (pwm, args, cb, data, 1);
1533 static gpg_error_t
1534 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
1536 int n, *intp;
1537 size_t *sizetp;
1538 char *arg1, **charpp;
1539 gpg_error_t rc = 0;
1541 if (!pwm)
1542 return GPG_ERR_INV_ARG;
1544 command_start (pwm);
1545 switch (opt)
1547 case PWMD_OPTION_SERVER_VERSION:
1548 if (!get)
1549 return GPG_ERR_NOT_SUPPORTED;
1551 if (!pwm)
1552 rc = GPG_ERR_INV_ARG;
1553 else if (!pwm->ctx)
1554 rc = GPG_ERR_INV_STATE;
1555 else
1557 unsigned *u = va_arg (ap, unsigned *);
1558 *u = pwm->version;
1561 break;
1562 case PWMD_OPTION_SIGPIPE:
1563 if (get)
1565 intp = va_arg (ap, int *);
1566 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
1567 break;
1570 n = va_arg (ap, int);
1571 if (n < 0 || n > 1)
1572 rc = GPG_ERR_INV_VALUE;
1574 if (n)
1575 pwm->opts |= OPT_SIGPIPE;
1576 else
1577 pwm->opts &= ~OPT_SIGPIPE;
1579 break;
1580 case PWMD_OPTION_LOCK_ON_OPEN:
1581 if (get)
1583 intp = va_arg (ap, int *);
1584 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
1585 break;
1588 n = va_arg (ap, int);
1590 if (n < 0 || n > 1)
1591 rc = GPG_ERR_INV_VALUE;
1593 if (n)
1594 pwm->opts |= OPT_LOCK_ON_OPEN;
1595 else
1596 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1598 break;
1599 case PWMD_OPTION_INQUIRE_TOTAL:
1600 if (get)
1602 sizetp = va_arg (ap, size_t *);
1603 *sizetp = pwm->inquire_total;
1604 break;
1607 pwm->inquire_total = va_arg (ap, size_t);
1608 break;
1609 case PWMD_OPTION_STATUS_CB:
1610 if (get)
1612 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
1614 *cb = pwm->status_func;
1615 break;
1618 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1619 break;
1620 case PWMD_OPTION_STATUS_DATA:
1621 if (get)
1623 void **data = va_arg (ap, void **);
1625 *data = pwm->status_data;
1626 break;
1629 pwm->status_data = va_arg (ap, void *);
1630 break;
1631 case PWMD_OPTION_NO_PINENTRY:
1632 if (get)
1634 intp = va_arg (ap, int *);
1635 *intp = pwm->disable_pinentry;
1636 break;
1639 n = va_arg (ap, int);
1641 if (n < 0 || n > 1)
1642 rc = GPG_ERR_INV_VALUE;
1643 else
1644 pwm->disable_pinentry = n;
1645 break;
1646 case PWMD_OPTION_LOCAL_PINENTRY:
1647 if (get)
1649 intp = va_arg (ap, int *);
1650 *intp = pwm->local_pinentry;
1651 break;
1654 n = va_arg (ap, int);
1656 if (n < 0 || n > 1)
1657 rc = GPG_ERR_INV_VALUE;
1658 else
1659 pwm->local_pinentry = n;
1661 break;
1662 case PWMD_OPTION_PINENTRY_TIMEOUT:
1663 if (get)
1665 intp = va_arg (ap, int *);
1666 *intp = pwm->pinentry_timeout;
1667 break;
1670 n = va_arg (ap, int);
1672 if (n < 0)
1673 rc = GPG_ERR_INV_VALUE;
1674 else
1675 pwm->pinentry_timeout = n;
1676 break;
1677 case PWMD_OPTION_PINENTRY_TRIES:
1678 if (get)
1680 intp = va_arg (ap, int *);
1681 *intp = pwm->pinentry_tries;
1682 break;
1685 n = va_arg (ap, int);
1686 pwm->pinentry_tries = n;
1687 break;
1688 case PWMD_OPTION_PINENTRY_PATH:
1689 if (get)
1691 charpp = va_arg (ap, char **);
1692 *charpp = pwm->pinentry_path;
1693 break;
1696 arg1 = va_arg (ap, char *);
1697 pwmd_free (pwm->pinentry_path);
1698 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1699 break;
1700 case PWMD_OPTION_PINENTRY_TTY:
1701 if (get)
1703 charpp = va_arg (ap, char **);
1704 *charpp = pwm->pinentry_tty;
1705 break;
1708 arg1 = va_arg (ap, char *);
1709 pwmd_free (pwm->pinentry_tty);
1710 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1711 break;
1712 case PWMD_OPTION_PINENTRY_DISPLAY:
1713 if (get)
1715 charpp = va_arg (ap, char **);
1716 *charpp = pwm->pinentry_display;
1717 break;
1720 arg1 = va_arg (ap, char *);
1721 pwmd_free (pwm->pinentry_display);
1722 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1723 break;
1724 case PWMD_OPTION_PINENTRY_TERM:
1725 if (get)
1727 charpp = va_arg (ap, char **);
1728 *charpp = pwm->pinentry_term;
1729 break;
1732 arg1 = va_arg (ap, char *);
1733 pwmd_free (pwm->pinentry_term);
1734 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1735 break;
1736 case PWMD_OPTION_PINENTRY_ERROR:
1737 if (get)
1739 charpp = va_arg (ap, char **);
1740 *charpp = pwm->pinentry_error;
1741 break;
1744 arg1 = va_arg (ap, char *);
1745 pwmd_free (pwm->pinentry_error);
1746 if (pwm->disable_pinentry)
1747 pwm->pinentry_error = arg1 ? pwmd_strdup (arg1) : NULL;
1748 else
1749 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1750 break;
1751 case PWMD_OPTION_PINENTRY_PROMPT:
1752 if (get)
1754 charpp = va_arg (ap, char **);
1755 *charpp = pwm->pinentry_prompt;
1756 break;
1759 arg1 = va_arg (ap, char *);
1760 pwmd_free (pwm->pinentry_prompt);
1761 if (pwm->disable_pinentry)
1762 pwm->pinentry_prompt = arg1 ? pwmd_strdup (arg1) : NULL;
1763 else
1764 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1765 break;
1766 case PWMD_OPTION_PINENTRY_DESC:
1767 if (get)
1769 charpp = va_arg (ap, char **);
1770 *charpp = pwm->pinentry_desc;
1771 break;
1774 arg1 = va_arg (ap, char *);
1775 pwmd_free (pwm->pinentry_desc);
1776 if (pwm->disable_pinentry)
1777 pwm->pinentry_desc = arg1 ? pwmd_strdup (arg1) : NULL;
1778 else
1779 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1780 break;
1781 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1782 if (get)
1784 charpp = va_arg (ap, char **);
1785 *charpp = pwm->pinentry_lcctype;
1786 break;
1789 arg1 = va_arg (ap, char *);
1790 pwmd_free (pwm->pinentry_lcctype);
1791 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1792 break;
1793 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1794 if (get)
1796 charpp = va_arg (ap, char **);
1797 *charpp = pwm->pinentry_lcmessages;
1798 break;
1801 arg1 = va_arg (ap, char *);
1802 pwmd_free (pwm->pinentry_lcmessages);
1803 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1804 break;
1805 case PWMD_OPTION_KNOWNHOST_CB:
1806 if (get)
1808 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
1810 *cb = pwm->kh_cb;
1811 break;
1814 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1815 break;
1816 case PWMD_OPTION_KNOWNHOST_DATA:
1817 if (get)
1819 void **data = va_arg (ap, void **);
1821 *data = pwm->kh_data;
1822 break;
1825 pwm->kh_data = va_arg (ap, void *);
1826 break;
1827 case PWMD_OPTION_SSH_AGENT:
1828 if (get)
1830 intp = va_arg (ap, int *);
1831 *intp = pwm->use_agent;
1832 break;
1835 pwm->use_agent = va_arg (ap, int);
1837 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1839 pwm->use_agent = 0;
1840 rc = GPG_ERR_INV_VALUE;
1842 break;
1843 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE:
1844 if (get)
1846 intp = va_arg (ap, int *);
1847 *intp = pwm->needs_passphrase;
1848 break;
1851 pwm->needs_passphrase = va_arg (ap, int);
1853 if (pwm->needs_passphrase < 0 || pwm->needs_passphrase > 1)
1855 pwm->needs_passphrase = 0;
1856 rc = GPG_ERR_INV_VALUE;
1858 break;
1859 case PWMD_OPTION_TLS_VERIFY:
1860 if (get)
1862 intp = va_arg (ap, int *);
1863 *intp = pwm->tls_verify;
1864 break;
1867 pwm->tls_verify = va_arg (ap, int);
1869 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1871 pwm->tls_verify = 0;
1872 rc = GPG_ERR_INV_VALUE;
1874 break;
1875 case PWMD_OPTION_SOCKET_TIMEOUT:
1876 if (get)
1878 intp = va_arg (ap, int *);
1879 *intp = pwm->socket_timeout;
1880 break;
1883 pwm->socket_timeout = va_arg (ap, int);
1884 if (pwm->socket_timeout < 0)
1886 pwm->socket_timeout = 0;
1887 rc = GPG_ERR_INV_VALUE;
1890 #ifdef WITH_SSH
1891 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1893 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1894 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1895 pwm->socket_timeout * 1000);
1897 #endif
1898 #ifdef WITH_GNUTLS
1899 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1900 pwm->tcp->tls->timeout = pwm->socket_timeout;
1901 #endif
1902 break;
1903 case PWMD_OPTION_OVERRIDE_INQUIRE:
1904 if (get)
1906 intp = va_arg (ap, int *);
1907 *intp = pwm->override_inquire;
1908 break;
1911 pwm->override_inquire = va_arg (ap, int);
1913 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1915 pwm->override_inquire = 0;
1916 rc = GPG_ERR_INV_VALUE;
1918 break;
1919 default:
1920 rc = GPG_ERR_UNKNOWN_OPTION;
1921 break;
1924 return FINISH (rc);
1927 gpg_error_t
1928 pwmd_setopt (pwm_t * pwm, int opt, ...)
1930 va_list ap;
1931 gpg_error_t rc = 0;
1933 va_start (ap, opt);
1934 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
1935 va_end (ap);
1936 return FINISH (rc);
1939 gpg_error_t
1940 pwmd_getopt (pwm_t *pwm, int opt, ...)
1942 va_list ap;
1943 gpg_error_t rc = 0;
1945 va_start (ap, opt);
1946 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
1947 va_end (ap);
1948 return FINISH (rc);
1951 gpg_error_t
1952 pwmd_new (const char *name, pwm_t ** pwm)
1954 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1955 gpg_error_t rc;
1957 if (!h)
1958 return FINISH (GPG_ERR_ENOMEM);
1960 if (name)
1962 h->name = pwmd_strdup (name);
1963 if (!h->name)
1965 pwmd_free (h);
1966 return FINISH (GPG_ERR_ENOMEM);
1970 reset_handle (h);
1971 h->pinentry_timeout = -1;
1972 h->current_pinentry_timeout = -1;
1973 h->pinentry_tries = 3;
1974 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1975 h->prot = PWMD_IP_ANY;
1976 #endif
1978 if (isatty (STDOUT_FILENO))
1980 char buf[256];
1981 int err = ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
1983 if (!err)
1985 h->pinentry_tty = pwmd_strdup (buf);
1986 if (!h->pinentry_tty)
1988 rc = GPG_ERR_ENOMEM;
1989 goto fail;
1994 if (getenv ("TERM") && h->pinentry_tty)
1996 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
1997 if (!h->pinentry_term)
1999 rc = GPG_ERR_ENOMEM;
2000 goto fail;
2004 if (getenv ("DISPLAY"))
2006 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
2007 if (!h->pinentry_display)
2009 rc = GPG_ERR_ENOMEM;
2010 goto fail;
2014 *pwm = h;
2015 return 0;
2017 fail:
2018 pwmd_close (h);
2019 return FINISH (rc);
2022 void
2023 pwmd_free (void *ptr)
2025 _xfree (ptr);
2028 void *
2029 pwmd_malloc (size_t size)
2031 return _xmalloc (size);
2034 void *
2035 pwmd_calloc (size_t nmemb, size_t size)
2037 return _xcalloc (nmemb, size);
2040 void *
2041 pwmd_realloc (void *ptr, size_t size)
2043 return _xrealloc (ptr, size);
2046 char *
2047 pwmd_strdup (const char *str)
2049 char *t;
2050 size_t len;
2051 register size_t c;
2053 len = strlen (str);
2054 t = _xmalloc ((len + 1) * sizeof (char));
2055 if (!t)
2056 return NULL;
2058 for (c = 0; c < len; c++)
2059 t[c] = str[c];
2061 t[c] = 0;
2062 return t;
2065 char *
2066 pwmd_strdup_printf (const char *fmt, ...)
2068 va_list ap, ap2;
2069 int len;
2070 char *buf;
2072 if (!fmt)
2073 return NULL;
2075 va_start (ap, fmt);
2076 va_copy (ap2, ap);
2077 len = vsnprintf (NULL, 0, fmt, ap);
2078 va_end (ap);
2079 buf = pwmd_malloc (++len);
2080 if (buf)
2081 vsnprintf (buf, len, fmt, ap2);
2083 va_end (ap2);
2084 return buf;
2087 gpg_error_t
2088 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
2089 size_t * len, pwmd_pinentry_t which)
2091 #ifndef WITH_PINENTRY
2092 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
2093 #else
2094 gpg_error_t rc;
2096 command_start (pwm);
2097 if (which == PWMD_PINENTRY_CONFIRM && pwm->disable_pinentry)
2099 rc = get_password (pwm, NULL, NULL, which, 1);
2100 return FINISH (rc);
2103 rc = _pwmd_getpin (pwm, filename, result, len, which);
2104 return FINISH (rc);
2105 #endif
2108 const char *
2109 pwmd_version ()
2111 return LIBPWMD_VERSION_STR;
2114 unsigned int
2115 pwmd_features ()
2117 unsigned int n = 0;
2119 #ifdef WITH_PINENTRY
2120 n |= PWMD_FEATURE_PINENTRY;
2121 #endif
2122 #ifdef WITH_SSH
2123 n |= PWMD_FEATURE_SSH;
2124 #endif
2125 #ifdef WITH_QUALITY
2126 n |= PWMD_FEATURE_CRACK;
2127 #endif
2128 #ifdef WITH_GNUTLS
2129 n |= PWMD_FEATURE_GNUTLS;
2130 #endif
2131 return n;
2134 gpg_error_t
2135 pwmd_fd (pwm_t * pwm, int *fd)
2137 if (!pwm || !fd)
2138 return FINISH (GPG_ERR_INV_ARG);
2140 if (pwm->fd == -1)
2141 return FINISH (GPG_ERR_INV_STATE);
2143 *fd = pwm->fd;
2144 return 0;
2147 void
2148 pwmd_set_pointer (pwm_t *pwm, void *data)
2150 pwm->user_data = data;
2153 void *
2154 pwmd_get_pointer (pwm_t *pwm)
2156 return pwm->user_data;
2160 pwmd_tls_error (pwm_t *pwm)
2162 #ifndef WITH_GNUTLS
2163 return 0;
2164 #else
2165 return pwm ? pwm->tls_error : 0;
2166 #endif
2170 pwmd_gnutls_error (pwm_t *pwm, const char **str)
2172 #ifndef WITH_GNUTLS
2173 return 0;
2174 #else
2175 if (str && pwm && pwm->tls_error)
2176 *str = gnutls_strerror (pwm->tls_error);
2178 return pwm ? pwm->tls_error : 0;
2179 #endif
2182 gpg_error_t
2183 pwmd_cancel (pwm_t *pwm)
2185 if (!pwm)
2186 return FINISH (GPG_ERR_INV_ARG);
2188 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2189 if (pwm->fd == -1 && !pwm->tcp)
2190 #else
2191 if (pwm->fd == -1)
2192 #endif
2193 return FINISH (GPG_ERR_INV_STATE);
2195 /* Can only cancel the connection for the time being. */
2196 if (pwm->connected)
2197 return FINISH (GPG_ERR_INV_STATE);
2199 pwm->cancel = 1;
2200 return 0;