contrib: Add helper to build Android dependencies.
[libpwmd.git] / src / libpwmd.c
blob7528fcc5d4f0064a074adfa0cefc103f5043eba6
1 /*
2 Copyright (C) 2006-2023 Ben Kibbey <bjk@luxsci.net>
4 This file is part of libpwmd.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License version 2.1 as published by the Free Software Foundation.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18 USA
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <time.h>
34 #ifdef HAVE_STRINGS_H
35 #include <strings.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #ifdef HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43 #ifdef HAVE_LIMITS_H
44 #include <limits.h>
45 #endif
47 #ifndef __MINGW32__
48 # ifdef HAVE_TERMIOS_H
49 # include <termios.h>
50 # endif
51 # ifdef HAVE_SYS_SOCKET_H
52 # include <sys/socket.h>
53 # endif
54 # include <sys/un.h>
55 # include <sys/wait.h>
56 # include <pwd.h>
57 # include <sys/select.h>
58 # ifdef HAVE_ERR_H
59 # include <err.h>
60 # endif
61 #endif
63 #include <libpwmd.h>
64 #include "util-string.h"
66 #ifndef LINE_MAX
67 #define LINE_MAX 2048
68 #endif
70 #include "mem.h"
71 #include "misc.h"
72 #include "types.h"
73 #include "version.h"
75 #ifdef WITH_PINENTRY
76 #include "pinentry.h"
77 #endif
79 #ifdef WITH_QUALITY
80 #include "zxcvbn.h"
81 #endif
83 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
84 #include <sys/types.h>
85 # ifndef __MINGW32__
86 # ifdef HAVE_SYS_SOCKET_H
87 # include <sys/socket.h>
88 # endif
89 # ifdef HAVE_NETDB_H
90 # include <netdb.h>
91 # endif
92 # ifdef HAVE_NETINET_IN_H
93 # include <netinet/in.h>
94 # endif
95 # endif
96 #endif
98 enum
100 PWMD_WHICH_NONE,
101 PWMD_WHICH_SAVE,
102 PWMD_WHICH_PASSWD,
103 PWMD_WHICH_GENKEY
106 #define TEST_BULK_OFFSET(a, b) (a -= b == a ? 0 : 1)
107 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
108 ? gpg_error(rc) : rc
110 typedef struct
112 size_t len;
113 void *buf;
114 pwm_t *pwm;
115 } membuf_t;
117 struct bulk_inquire_s
119 pwm_t *pwm;
120 const char *data;
121 size_t size;
122 void *user;
123 pwmd_inquire_cb_t func;
126 static gpg_error_t status_cb (void *data, const char *line);
128 ssize_t
129 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
131 pwm_t *pwm = assuan_get_pointer (ctx);
133 if (pwm->read_cb)
134 return pwm->read_cb (pwm->read_cb_data, HANDLE2SOCKET (fd), data, len);
136 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
137 #ifdef WITH_SSH
138 if (pwm && pwm->tcp && pwm->tcp->ssh)
140 ssize_t ret = read_hook_ssh (pwm->tcp->ssh, fd, data, len);
142 if (ret == -1)
144 int e = errno;
146 __assuan_close (ctx, pwm->fd);
147 pwm->fd = ASSUAN_INVALID_FD;
148 errno = e;
151 return ret;
153 #endif
154 #ifdef WITH_GNUTLS
155 if (pwm && pwm->tcp && pwm->tcp->tls)
156 return tls_read_hook (pwm, fd, data, len);
157 #endif
158 #endif
160 return read (HANDLE2SOCKET (fd), data, len);
163 ssize_t
164 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
165 size_t len)
167 pwm_t *pwm = assuan_get_pointer (ctx);
168 ssize_t wrote;
170 if (pwm->write_cb)
171 return pwm->write_cb (pwm->write_cb_data, HANDLE2SOCKET (fd), data, len);
173 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
174 #ifdef WITH_SSH
175 if (pwm && pwm->tcp && pwm->tcp->ssh)
177 ssize_t ret = write_hook_ssh (pwm->tcp->ssh, fd, data, len);
179 if (ret == -1)
181 int e = errno;
183 __assuan_close (ctx, pwm->fd);
184 pwm->fd = ASSUAN_INVALID_FD;
185 errno = e;
188 return ret;
190 #endif
191 #ifdef WITH_GNUTLS
192 if (pwm && pwm->tcp && pwm->tcp->tls)
193 return tls_write_hook (pwm, fd, data, len);
194 #endif
195 #endif
197 /* libassuan cannot handle EAGAIN when doing writes. */
200 wrote = write (HANDLE2SOCKET (fd), data, len);
201 if (wrote == -1 && errno == EAGAIN)
202 __assuan_usleep (pwm->ctx, 50000);
204 while (wrote == -1 && errno == EAGAIN);
206 return wrote;
209 #ifndef __MINGW32__
210 pid_t
211 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
212 int options)
214 (void)ctx;
215 (void)action;
216 return waitpid (pid, status, options);
218 #endif
220 gpg_error_t
221 pwmd_init ()
223 static int initialized;
225 #ifdef WITH_GNUTLS
226 // May be called more than once.
227 gnutls_global_init ();
228 #endif
230 if (initialized)
231 return 0;
233 #ifdef ENABLE_NLS
234 bindtextdomain ("libpwmd", LOCALEDIR);
235 #endif
236 #ifdef WITH_SSH
237 libssh2_init (0);
238 #endif
239 #ifndef MEM_DEBUG
240 gpgrt_set_alloc_func (_xrealloc_gpgrt);
241 #endif
242 gpgrt_init ();
244 #ifdef WITH_QUALITY
245 ZxcvbnInit (NULL);
246 #endif
248 initialized = 1;
249 return 0;
252 void
253 pwmd_deinit ()
255 gpg_err_deinit (0);
256 #ifdef WITH_GNUTLS
257 gnutls_global_deinit ();
258 #endif
259 #ifdef WITH_QUALITY
260 ZxcvbnUnInit();
261 #endif
264 static gpg_error_t
265 bulk_inquire_cb (void *user, const char *keyword, gpg_error_t rc,
266 char **data, size_t * size)
268 struct bulk_inquire_s *inq = user;
269 pwm_t *pwm = inq->pwm;
271 if (pwm->bulk_id && inq->func && inq->func != bulk_inquire_cb)
273 rc = inq->func (inq->user, keyword, rc, data, size);
274 return rc;
276 else if (pwm->bulk_id)
277 return rc ? rc : GPG_ERR_ASS_NO_INQUIRE_CB;
279 if (rc)
280 return rc;
282 *data = (char *)inq->data;
283 *size = inq->size;
284 return GPG_ERR_EOF;
287 gpg_error_t
288 _connect_finalize (pwm_t * pwm)
290 gpg_error_t rc = 0;
291 assuan_fd_t active[2];
292 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
293 char *bulk = NULL;
294 size_t offset = 0, toffset;
295 gpg_error_t rcs[] = { 0, GPG_ERR_MISSING_ERRNO };
297 if (n <= 0)
298 return GPG_ERR_EBADFD;
300 pwm->fd = active[0];
301 #ifdef WITH_PINENTRY
302 pwm->pinentry_pid = -1;
303 #endif
305 rc = pwmd_bulk_append (&bulk, "VERSION", strlen ("VERSION"), "GETINFO",
306 "VERSION", strlen ("VERSION"), &offset);
307 toffset = offset;
308 if (!rc && (pwm->opts & OPT_STATE_STATUS))
310 char *buf = pwmd_strdup_printf ("client-state=1");
312 if (buf)
313 rc = pwmd_bulk_append_rc (&bulk, rcs, "STATE", 5, "OPTION", buf,
314 strlen (buf), &offset);
315 else
316 rc = GPG_ERR_ENOMEM;
318 pwmd_free (buf);
321 if (!rc && pwm->name)
323 char *buf = pwmd_strdup_printf ("NAME=%s", pwm->name);
325 TEST_BULK_OFFSET (offset, toffset);
326 if (buf)
327 rc = pwmd_bulk_append_rc (&bulk, rcs, "NAME", strlen ("NAME"), "OPTION",
328 buf, strlen (buf), &offset);
329 else
330 rc = GPG_ERR_ENOMEM;
332 pwmd_free (buf);
335 if (!rc)
336 rc = pwmd_bulk_finalize (&bulk);
338 if (!rc)
340 char *result = NULL;
341 size_t size;
343 rc = pwmd_bulk (pwm, &result, &size, NULL, NULL, bulk, strlen (bulk));
344 pwmd_free (bulk);
345 bulk = NULL;
346 if (!rc)
348 const char *r;
349 gpg_error_t rrc;
350 size_t rsize;
352 offset = 0;
353 rc = pwmd_bulk_result (result, size, "STATE", 5, &offset, &r,
354 &rsize, &rrc);
355 if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
356 rc = 0;
357 else if (!rc)
358 rc = rrc;
360 if (!rc)
361 rc = pwmd_bulk_result (result, size, "VERSION", 7, &offset, &r,
362 &rsize, &rrc);
363 if (!rc && !rrc)
364 pwm->version = strtoul (r, NULL, 16);
366 if (!rc && !rrc)
367 rc = pwmd_bulk_result (result, size, "NAME", 4, &offset, &r,
368 &rsize, &rrc);
370 if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
371 rc = 0;
373 if (!rc)
374 rc = rrc;
376 pwmd_free (result);
380 pwmd_free (bulk);
381 return rc;
384 static gpg_error_t
385 connect_uds (pwm_t * pwm, const char *path)
387 #ifdef __MINGW32__
388 return GPG_ERR_UNSUPPORTED_PROTOCOL;
389 #else
390 if (!pwm)
391 return GPG_ERR_INV_ARG;
393 char *socketpath = NULL;
394 struct passwd pw;
395 char *pwbuf;
396 gpg_error_t rc;
398 pwbuf = _getpwuid (&pw);
399 if (!pwbuf)
400 return gpg_error_from_syserror ();
402 if (!path || !*path)
403 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
404 else
405 socketpath = _expand_homedir ((char *) path, &pw);
407 pwmd_free (pwbuf);
408 if (!socketpath)
409 return GPG_ERR_ENOMEM;
411 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
412 pwmd_free (socketpath);
413 return rc ? rc : _connect_finalize (pwm);
414 #endif
417 static gpg_error_t
418 init_handle (pwm_t * pwm)
420 gpg_error_t rc;
421 static struct assuan_malloc_hooks mhooks = {
422 pwmd_malloc, pwmd_realloc, pwmd_free
424 static struct assuan_system_hooks shooks = {
425 ASSUAN_SYSTEM_HOOKS_VERSION,
426 __assuan_usleep,
427 __assuan_pipe,
428 __assuan_close,
429 hook_read,
430 hook_write,
431 //FIXME
432 NULL, //recvmsg
433 NULL, //sendmsg both are used for FD passing
434 __assuan_spawn,
435 #ifdef __MINGW32__
436 __assuan_waitpid,
437 #else
438 hook_waitpid,
439 #endif
440 __assuan_socketpair,
441 __assuan_socket,
442 __assuan_connect
445 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
446 NULL);
447 if (rc)
448 return rc;
450 assuan_set_pointer (pwm->ctx, pwm);
451 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
452 return 0;
455 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
456 void
457 free_tcp (pwm_t *pwm)
459 struct tcp_s *tcp = pwm->tcp;
461 if (!tcp)
462 return;
464 #ifdef WITH_SSH
465 _free_ssh_conn (tcp->ssh);
466 #endif
467 #ifdef WITH_GNUTLS
468 tls_free (pwm);
469 #endif
471 pwmd_free (tcp->host);
472 if (tcp->addrs)
474 freeaddrinfo (tcp->addrs);
475 tcp->addrs = NULL;
478 pthread_cond_destroy (&tcp->dns_cond);
479 pthread_mutex_destroy (&tcp->dns_mutex);
480 pwmd_free (tcp);
481 pwm->tcp = NULL;
484 static gpg_error_t
485 lookup_host (pwm_t *pwm)
487 struct addrinfo hints = { 0 };
488 char portstr[6];
489 int n;
491 switch (pwm->prot)
493 case PWMD_IP_ANY:
494 hints.ai_family = AF_UNSPEC;
495 break;
496 case PWMD_IPV4:
497 hints.ai_family = AF_INET;
498 break;
499 case PWMD_IPV6:
500 hints.ai_family = AF_INET6;
501 break;
504 hints.ai_socktype = SOCK_STREAM;
505 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
506 n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
507 if (!n)
508 return 0;
510 switch (n)
512 #ifndef __MINGW32__
513 case EAI_SYSTEM:
514 return gpg_error_from_syserror ();
515 #endif
516 case EAI_AGAIN:
517 return GPG_ERR_EAGAIN;
518 case EAI_MEMORY:
519 return GPG_ERR_ENOMEM;
520 case EAI_NONAME:
521 return GPG_ERR_UNKNOWN_HOST;
522 default:
523 break;
526 return GPG_ERR_DNS_UNKNOWN;
529 #ifndef __MINGW32__
530 static void *
531 resolve_host_thread (void *arg)
533 pwm_t *pwm = arg;
534 gpg_error_t *n = pwmd_malloc (sizeof (gpg_error_t));
536 pthread_cleanup_push (pwmd_free, n);
537 *n = lookup_host (pwm);
538 pthread_cleanup_pop (0);
539 pthread_cond_broadcast (&pwm->tcp->dns_cond);
540 pwm->tcp->flags |= TCP_FLAG_DNS_FINISHED;
541 pthread_exit (n);
542 return n;
544 #endif
546 gpg_error_t
547 tcp_connect_common (pwm_t * pwm)
549 gpg_error_t rc = 0;
550 int n;
551 #ifndef __MINGW32__
552 #define TS_TIMEOUT 50000000L
553 pthread_t tid;
554 time_t now;
556 pwm->tcp->flags &= ~TCP_FLAG_DNS_FINISHED;
557 time (&now);
558 n = pthread_create (&tid, NULL, resolve_host_thread, pwm);
559 if (n)
560 return gpg_error_from_errno (n);
562 pthread_mutex_lock (&pwm->tcp->dns_mutex);
564 for (;;)
566 struct timespec ts;
567 gpg_error_t *result = NULL;
569 clock_gettime (CLOCK_REALTIME, &ts);
570 if (ts.tv_nsec + TS_TIMEOUT >= 1000000000LL) {
571 ts.tv_sec++;
572 ts.tv_nsec = 0;
574 else
575 ts.tv_nsec += TS_TIMEOUT;
577 if (pwm->cancel)
579 #ifdef HAVE_PTHREAD_CANCEL
580 pthread_cancel (tid);
581 pthread_join (tid, NULL);
582 #else
583 pthread_join (tid, (void **)&result);
584 pwmd_free (result);
585 #endif
586 return GPG_ERR_CANCELED;
589 n = pthread_cond_timedwait (&pwm->tcp->dns_cond, &pwm->tcp->dns_mutex,
590 &ts);
591 if (n == ETIMEDOUT && !(pwm->tcp->flags & TCP_FLAG_DNS_FINISHED))
593 if (pwm->socket_timeout && ts.tv_sec - now >= pwm->socket_timeout)
595 #ifdef HAVE_PTHREAD_CANCEL
596 pthread_cancel (tid);
597 pthread_join (tid, NULL);
598 #else
599 pthread_join (tid, (void **)&result);
600 pwmd_free (result);
601 #endif
602 return GPG_ERR_ETIMEDOUT;
605 continue;
607 else if (n && n != ETIMEDOUT)
609 #ifdef HAVE_PTHREAD_CANCEL
610 pthread_cancel (tid);
611 pthread_join (tid, NULL);
612 #else
613 pthread_join (tid, (void **)&result);
614 pwmd_free (result);
615 #endif
616 return gpg_error_from_errno (n);
619 /* It shouldn't happen, but it does. Noticable when running under
620 * Valgrind: the pthread_cond_broadcast() is never heard yet the thread
621 * returns with the value set. */
622 if (pwm->tcp->flags & TCP_FLAG_DNS_FINISHED)
624 pthread_join (tid, (void **)&result);
625 rc = *result;
626 pwmd_free (result);
627 break;
630 #else
631 rc = lookup_host (pwm);
632 #endif
634 if (rc)
635 return rc;
637 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
638 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
640 #ifdef __MINGW32__
641 pwm->fh = _open_osfhandle (socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0), 0);
642 pwm->fd = SOCKET2HANDLE (_get_osfhandle (pwm->fh));
643 #else
644 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
645 #endif
646 if (pwm->fd == ASSUAN_INVALID_FD)
648 rc = gpg_error_from_syserror ();
649 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
650 break;
651 continue;
654 rc = set_non_blocking (pwm->fd, 1);
655 if (rc)
657 __assuan_close (pwm->ctx, pwm->fd);
658 pwm->fd = ASSUAN_INVALID_FD;
659 break;
662 if (connect (HANDLE2SOCKET (pwm->fd), pwm->tcp->addr->ai_addr,
663 pwm->tcp->addr->ai_family == AF_INET6
664 ? sizeof (struct sockaddr_in6)
665 : sizeof (struct sockaddr)) == -1)
667 struct timeval tv;
668 fd_set wfds;
669 unsigned elapsed = 0;
671 rc = gpg_error_from_syserror ();
672 #ifdef __MINGW32__
673 int w = WSAGetLastError ();
674 switch (w)
676 case WSAEINPROGRESS:
677 case WSAEWOULDBLOCK:
678 rc = GPG_ERR_EINPROGRESS;
679 break;
680 default:
681 break;
683 #endif
685 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
687 __assuan_close (pwm->ctx, pwm->fd);
688 pwm->fd = ASSUAN_INVALID_FD;
689 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
690 return rc;
691 continue;
694 again:
695 tv.tv_sec = 1;
696 tv.tv_usec = 0;
697 FD_ZERO (&wfds);
698 FD_SET (HANDLE2SOCKET (pwm->fd), &wfds);
699 n = select (HANDLE2SOCKET (pwm->fd)+1, NULL, &wfds, NULL, &tv);
700 rc = 0;
701 if (!n || pwm->cancel)
703 if (pwm->cancel)
704 rc = gpg_error (GPG_ERR_CANCELED);
705 else if (++elapsed >= pwm->socket_timeout)
706 rc = gpg_error (GPG_ERR_ETIMEDOUT);
707 else
708 goto again;
710 else if (n != -1)
712 socklen_t len = sizeof (int);
713 #ifdef __MINGW32__
714 char ret;
716 len = sizeof (char);
717 getsockopt (HANDLE2SOCKET (pwm->fd), SOL_SOCKET, SO_ERROR, &ret, &len);
718 if (ret)
719 rc = gpg_error_from_errno (ret);
720 #else
721 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
722 if (n)
723 rc = gpg_error_from_errno (n);
724 #endif
726 else if (n == -1)
727 rc = gpg_error_from_syserror ();
729 if (rc)
731 __assuan_close (pwm->ctx, pwm->fd);
732 pwm->fd = ASSUAN_INVALID_FD;
733 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
734 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT
735 || pwm->cancel)
736 return rc;
738 else
739 break;
741 else
742 break;
745 if (!rc)
747 rc = set_non_blocking (pwm->fd, 0);
748 if (rc)
750 __assuan_close (pwm->ctx, pwm->fd);
751 pwm->fd = ASSUAN_INVALID_FD;
755 return rc;
757 #endif
759 static void
760 command_start (pwm_t *pwm)
762 pwm->pin_repeated = 0;
763 pwm->cancel = 0;
766 gpg_error_t
767 pwmd_connect_fd (pwm_t * pwm, int fd)
769 gpg_error_t rc = 0;
771 if (!pwm)
772 return FINISH (GPG_ERR_INV_ARG);
773 else if (!pwm->ctx)
775 rc = init_handle (pwm);
776 if (rc)
777 return FINISH (rc);
779 else if (pwm->fd != ASSUAN_INVALID_FD)
780 return FINISH (GPG_ERR_INV_STATE);
782 command_start (pwm);
784 #ifndef __MINGW32__
785 if (!(pwm->opts & OPT_SIGPIPE))
787 struct sigaction sa = { 0 };
789 sa.sa_handler = SIG_IGN;
790 sigaction (SIGPIPE, &sa, NULL);
792 #endif
794 rc = assuan_socket_connect_fd (pwm->ctx, fd, 0);
795 if (!rc)
797 pwm->fd = SOCKET2HANDLE (fd);
798 pwm->connected = pwm->user_fd = 1;
799 rc = _connect_finalize (pwm);
802 if (rc)
803 pwmd_disconnect (pwm);
805 return FINISH (rc);
808 gpg_error_t
809 pwmd_connect (pwm_t * pwm, const char *url, ...)
811 const char *p = url;
812 gpg_error_t rc;
814 if (!pwm)
815 return FINISH (GPG_ERR_INV_ARG);
816 else if (!pwm->ctx)
818 rc = init_handle (pwm);
819 if (rc)
820 return FINISH (GPG_ERR_INV_ARG);
822 else if (pwm->fd != ASSUAN_INVALID_FD)
823 return FINISH (GPG_ERR_INV_STATE);
825 command_start (pwm);
827 #ifndef __MINGW32__
828 if (!(pwm->opts & OPT_SIGPIPE))
830 struct sigaction sa = { 0 };
832 sa.sa_handler = SIG_IGN;
833 sigaction (SIGPIPE, &sa, NULL);
835 #endif
837 #ifdef WITH_GNUTLS
838 pwm->tls_error = 0;
839 #endif
840 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
842 if (p && (*p == '/' || *p == '~'))
843 rc = connect_uds (pwm, p);
844 else if (!p || !strncmp (p, "file://", 7))
846 if (p)
847 p += 7;
848 #ifdef DEFAULT_PWMD_SOCKET
849 else
850 p = DEFAULT_PWMD_SOCKET;
851 #endif
852 rc = connect_uds (pwm, p);
854 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
855 !strncmp (p, "ssh4://", 7))
857 #ifndef WITH_SSH
858 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
859 #else
860 char *host = NULL;
861 int port;
862 char *username = NULL;
864 if (!strncmp (p, "ssh6://", 7))
866 pwm->prot = PWMD_IPV6;
867 p += 7;
869 else if (!strncmp (p, "ssh4://", 7))
871 pwm->prot = PWMD_IPV4;
872 p += 7;
874 else
876 pwm->prot = PWMD_IP_ANY;
877 p += 6;
880 rc = _parse_ssh_url (p, &host, &port, &username);
881 if (!rc)
883 va_list ap;
884 char *identity = NULL;
885 char *knownhosts = NULL;
887 va_start (ap, url);
888 identity = va_arg (ap, char *);
890 if (!identity && pwm->use_agent != 1)
891 rc = GPG_ERR_INV_ARG;
892 else
893 knownhosts = va_arg (ap, char *);
895 va_end (ap);
897 if (!rc)
898 rc = _do_ssh_connect (pwm, host, port, identity, username,
899 knownhosts);
900 if (!rc)
902 rc = _connect_finalize (pwm);
903 if (rc)
904 free_tcp (pwm);
908 pwmd_free (host);
909 pwmd_free (username);
910 pwm->local_pinentry = 1;
911 pwmd_free (pwm->ssh_passphrase);
912 pwm->ssh_passphrase = NULL;
913 #endif
915 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
916 !strncmp (p, "tls4://", 7))
918 #ifndef WITH_GNUTLS
919 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
920 #else
921 char *host = NULL;
922 int port;
924 if (!strncmp (p, "tls6://", 7))
926 pwm->prot = PWMD_IPV6;
927 p += 7;
929 else if (!strncmp (p, "tls4://", 7))
931 pwm->prot = PWMD_IPV4;
932 p += 7;
934 else
936 pwm->prot = PWMD_IP_ANY;
937 p += 6;
940 rc = tls_parse_url (p, &host, &port);
941 if (!rc)
943 va_list ap;
944 char *clientcert = NULL;
945 char *clientkey = NULL;
946 char *cacert = NULL;
947 char *server_fp = NULL;
949 va_start (ap, url);
950 clientcert = va_arg (ap, char *);
952 if (!clientcert)
953 rc = GPG_ERR_INV_ARG;
954 else
956 clientkey = va_arg (ap, char *);
957 if (!clientkey)
958 rc = GPG_ERR_INV_ARG;
959 else
961 cacert = va_arg (ap, char *);
962 if (!cacert)
963 rc = GPG_ERR_INV_ARG;
964 else
965 server_fp = va_arg (ap, char *);
969 va_end (ap);
971 if (!rc)
972 rc = tls_connect (pwm, host, port, clientcert, clientkey, cacert,
973 pwm->tls_priority, server_fp, pwm->tls_verify);
974 if (!rc)
976 rc = _connect_finalize (pwm);
977 if (rc)
978 free_tcp (pwm);
982 pwmd_free (host);
983 pwm->local_pinentry = 1;
984 #endif
987 if (!rc)
988 pwm->connected = 1;
990 return FINISH (rc);
993 static void
994 disconnect (pwm_t * pwm)
996 if (!pwm)
997 return;
999 if (pwm->ctx)
1000 assuan_release (pwm->ctx);
1002 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1003 free_tcp (pwm);
1004 #endif
1005 pwm->ctx = NULL;
1006 pwm->fd = ASSUAN_INVALID_FD;
1007 pwm->connected = 0;
1008 pwm->user_fd = -1;
1011 void
1012 pwmd_close (pwm_t * pwm)
1014 if (!pwm)
1015 return;
1017 disconnect (pwm);
1018 pwmd_free (pwm->pinentry_error);
1019 pwmd_free (pwm->pinentry_desc);
1020 pwmd_free (pwm->pinentry_prompt);
1021 pwmd_free (pwm->pinentry_tty);
1022 pwmd_free (pwm->pinentry_display);
1023 pwmd_free (pwm->pinentry_term);
1024 pwmd_free (pwm->pinentry_lcctype);
1025 pwmd_free (pwm->pinentry_lcmessages);
1026 pwmd_free (pwm->filename);
1027 pwmd_free (pwm->name);
1028 pwmd_free (pwm->passphrase_info);
1029 pwmd_free (pwm->passphrase_hint);
1030 pwmd_free (pwm->ssh_passphrase);
1031 pwmd_free (pwm->tls_priority);
1033 #ifdef WITH_PINENTRY
1034 if (pwm->pctx)
1035 _pinentry_disconnect (pwm);
1036 #endif
1038 pwmd_free (pwm);
1041 static gpg_error_t
1042 inquire_realloc_cb (void *data, const void *buffer, size_t len)
1044 membuf_t *mem = (membuf_t *) data;
1045 void *p;
1046 gpg_error_t rc = 0;
1048 if (!buffer)
1049 return 0;
1051 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
1052 return gpg_error (GPG_ERR_ENOMEM);
1054 mem->buf = p;
1055 memcpy ((char *) mem->buf + mem->len, buffer, len);
1056 mem->len += len;
1058 if (mem->pwm->version >= 0x030101 && len > 1 && mem->pwm->status_func)
1060 char buf[ASSUAN_LINELENGTH];
1062 snprintf (buf, sizeof (buf), "XFER %zu %zu", mem->len,
1063 mem->pwm->data_total);
1064 rc = mem->pwm->status_func (mem->pwm->status_data, buf);
1067 return rc;
1070 static gpg_error_t
1071 get_password (pwm_t * pwm, char **result, size_t * len,
1072 pwmd_pinentry_t w, int echo)
1074 char buf[ASSUAN_LINELENGTH+1] = { 0 }, *p;
1075 #ifndef __MINGW32__
1076 struct termios told, tnew;
1077 #endif
1078 char *key = NULL;
1080 if (result)
1081 *result = NULL;
1083 if (len)
1084 *len = 0;
1086 if (!isatty (STDIN_FILENO))
1088 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
1089 return GPG_ERR_ENOTTY;
1092 #ifndef __MINGW32__
1093 if (!echo)
1095 if (tcgetattr (STDIN_FILENO, &told) == -1)
1096 return gpg_error_from_syserror ();
1098 memcpy (&tnew, &told, sizeof (struct termios));
1099 tnew.c_lflag &= ~(ECHO);
1100 tnew.c_lflag |= ICANON | ECHONL;
1102 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
1104 int n = errno;
1106 tcsetattr (STDIN_FILENO, TCSANOW, &told);
1107 return gpg_error_from_errno (n);
1110 #endif
1112 if (pwm->passphrase_hint)
1113 fprintf(stderr, N_("Key info: %s\n"), pwm->passphrase_hint);
1115 switch (w)
1117 case PWMD_PINENTRY_OPEN:
1118 fprintf (stderr, N_("Passphrase for %s: "), pwm->filename);
1119 break;
1120 case PWMD_PINENTRY_OPEN_FAILED:
1121 fprintf (stderr, N_("Invalid passphrase. Passphrase for %s: "),
1122 pwm->filename);
1123 break;
1124 case PWMD_PINENTRY_SAVE:
1125 fprintf (stderr, N_("New passphrase for %s: "), pwm->filename);
1126 break;
1127 case PWMD_PINENTRY_SAVE_CONFIRM:
1128 fprintf (stderr, N_("Repeat passphrase: "));
1129 break;
1130 case PWMD_PINENTRY_CONFIRM:
1131 if (pwm->pinentry_desc)
1132 fprintf (stderr, "%s", pwm->pinentry_desc);
1134 if (pwm->pinentry_prompt)
1135 fprintf (stderr, "%s", pwm->pinentry_prompt);
1136 else
1137 fprintf(stderr, N_("Confirm [y/N]:"));
1138 default:
1139 break;
1142 p = fgets (buf, sizeof (buf), stdin);
1144 #ifndef __MINGW32__
1145 if (!echo)
1146 tcsetattr (STDIN_FILENO, TCSANOW, &told);
1147 #endif
1149 if (!p || feof (stdin))
1151 clearerr (stdin);
1152 return GPG_ERR_CANCELED;
1155 /* Strip the newline character. */
1156 p[strlen (p) - 1] = 0;
1158 if (buf[0])
1160 if (w == PWMD_PINENTRY_CONFIRM)
1162 if (*p != 'y' && *p != 'Y')
1163 return GPG_ERR_CANCELED;
1164 return 0;
1167 key = pwmd_strdup_printf ("%s", p);
1168 wipememory (buf, 0, sizeof (buf));
1169 if (!key)
1170 return GPG_ERR_ENOMEM;
1172 if (result)
1173 *result = key;
1175 if (len)
1176 *len = strlen (key);
1178 else
1180 if (w == PWMD_PINENTRY_CONFIRM)
1181 return GPG_ERR_CANCELED;
1183 /* To satisfy inquire_cb(). */
1184 if (result)
1185 *result = pwmd_strdup ("");
1187 if (len)
1188 *len = 1;
1191 return 0;
1194 gpg_error_t
1195 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
1197 gpg_error_t rc;
1198 int new_password = 0;
1199 char *password = NULL, *newpass = NULL;
1200 int error = 0;
1202 command_start (pwm);
1204 if (data)
1205 *data = NULL;
1207 if (size)
1208 *size = 0;
1210 if (!strcmp (keyword, "NEW_PASSPHRASE"))
1211 new_password = 1;
1213 if (!new_password && pwm->pinentry_try)
1214 error = 1;
1216 again:
1217 if (pwm->disable_pinentry)
1219 rc = get_password (pwm, &password, size,
1220 new_password ? PWMD_PINENTRY_SAVE :
1221 error ? PWMD_PINENTRY_OPEN_FAILED :
1222 PWMD_PINENTRY_OPEN, 0);
1223 if (!rc && new_password)
1224 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
1227 else
1229 pwmd_pinentry_t which;
1231 if (error)
1232 which = new_password
1233 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
1234 else
1235 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
1237 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
1238 if (!rc && new_password && !pwm->pin_repeated)
1239 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
1240 PWMD_PINENTRY_SAVE_CONFIRM);
1243 if (!rc && new_password)
1245 if (!pwm->pin_repeated && ((!password && newpass)
1246 || (!newpass && password) || (newpass && password &&
1247 strcmp (newpass, password))))
1249 if (pwm->disable_pinentry)
1250 fprintf (stderr, N_("Passphrases do not match.\n"));
1252 pwmd_free (password);
1253 pwmd_free (newpass);
1254 password = newpass = NULL;
1255 error = 1;
1256 goto again;
1260 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
1261 pwmd_free (newpass);
1262 if (!rc && data)
1263 *data = password;
1264 else
1265 pwmd_free (password);
1267 return rc;
1270 static gpg_error_t
1271 inquire_cb (void *data, const char *keyword)
1273 pwm_t *pwm = (pwm_t *) data;
1274 gpg_error_t rc = 0;
1275 int free_result = 0;
1276 char *result = NULL;
1277 int is_password = 0;
1278 int new_password = 0;
1280 if (!strcmp (keyword, "PASSPHRASE") || !strcmp (keyword, "SIGN_PASSPHRASE"))
1281 is_password = 1;
1282 else if (!strcmp (keyword, "NEW_PASSPHRASE") || !strcmp (keyword, "GENKEY"))
1283 new_password = 1;
1285 /* Shouldn't get this far without a callback. */
1286 if (!pwm->override_inquire && !pwm->inquire_func
1287 && !is_password && !new_password)
1288 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
1290 for (;;)
1292 size_t len = 0;
1293 gpg_error_t arc;
1295 result = NULL;
1297 if (!pwm->override_inquire && (is_password || new_password))
1299 free_result = 1;
1300 rc = pwmd_password (data, keyword, &result, &len);
1301 if (!rc)
1302 rc = GPG_ERR_EOF;
1304 else
1305 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
1306 &len);
1308 /* gpg will truncate a passphrase at the first nil byte which may be bad
1309 * for generated key files. */
1310 if ((!rc || gpg_err_code (rc) == GPG_ERR_EOF)
1311 && (is_password || new_password))
1313 if (len && result && *result)
1315 for (size_t n = 0; n < len; n++)
1317 if (result[n] == 0 && n+1 != len)
1318 rc = GPG_ERR_INV_PASSPHRASE;
1323 cancel:
1324 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
1326 #ifndef LIBASSUAN_2_1_0
1327 gpg_error_t trc = rc;
1329 /* Cancel this inquire. */
1330 rc = assuan_send_data (pwm->ctx, NULL, 1);
1331 if (!rc)
1333 char *line;
1334 size_t len;
1336 /* There is a bug (or feature?) in assuan_send_data() that
1337 * when cancelling an inquire the next read from the server is
1338 * not done until the next command making the next command
1339 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
1341 rc = assuan_read_line (pwm->ctx, &line, &len);
1343 /* Restore the original error. This differs from the error
1344 * returned from the pwmd command (GPG_ERR_CANCELED). This
1345 * error is returned to the calling function.
1347 if (!rc)
1348 rc = trc;
1350 #endif
1351 break;
1354 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
1356 if (len <= 0 && !result)
1358 rc = 0;
1359 break;
1361 else if ((len <= 0 && result) || (len && !result))
1363 rc = gpg_error (GPG_ERR_INV_ARG);
1364 break;
1367 if (pwm->inquire_maxlen
1368 && pwm->inquire_sent + len > pwm->inquire_maxlen)
1370 rc = gpg_error (GPG_ERR_TOO_LARGE);
1371 if (!free_result)
1372 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
1373 &result, &len);
1374 goto cancel;
1377 arc = assuan_send_data (pwm->ctx, result, len);
1378 if (gpg_err_code (rc) == GPG_ERR_EOF)
1380 rc = arc;
1381 break;
1384 rc = arc;
1386 else if (rc)
1387 break;
1389 if (!rc)
1391 pwm->inquire_sent += len;
1393 if (pwm->status_func)
1395 char buf[ASSUAN_LINELENGTH];
1397 snprintf (buf, sizeof (buf), "XFER %zu %zu", pwm->inquire_sent,
1398 pwm->inquire_total);
1399 rc = pwm->status_func (pwm->status_data, buf);
1400 if (rc)
1401 continue;
1406 if (free_result)
1407 pwmd_free (result);
1409 pwm->inquire_maxlen = pwm->inquire_sent = 0;
1410 return rc;
1413 static gpg_error_t
1414 parse_assuan_line (pwm_t * pwm)
1416 gpg_error_t rc;
1417 char *line;
1418 size_t len;
1420 rc = assuan_read_line (pwm->ctx, &line, &len);
1421 if (!rc)
1423 if (line[0] == 'O' && line[1] == 'K' &&
1424 (line[2] == 0 || line[2] == ' '))
1427 else if (line[0] == '#')
1430 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
1432 rc = status_cb (pwm, line[1] == 0 ? line + 1 : line + 2);
1434 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
1435 (line[3] == 0 || line[3] == ' '))
1437 line += 4;
1438 rc = strtol (line, NULL, 10);
1442 return rc;
1445 static void
1446 reset_handle (pwm_t *pwm)
1448 pwm->fd = ASSUAN_INVALID_FD;
1449 pwm->user_fd = -1;
1450 pwm->cancel = 0;
1451 pwm->pinentry_disabled = 0;
1452 pwm->lock_timeout = -2;
1453 #ifdef WITH_PINENTRY
1454 if (pwm->pctx)
1455 _pinentry_disconnect (pwm);
1456 #endif
1457 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1458 #ifdef WITH_GNUTLS
1459 pwm->tls_error = 0;
1460 #endif
1462 if (pwm->tcp)
1464 pwm->tcp->rc = 0;
1466 #endif
1469 gpg_error_t
1470 pwmd_disconnect (pwm_t * pwm)
1472 if (!pwm)
1473 return FINISH (GPG_ERR_INV_ARG);
1475 command_start (pwm);
1477 if (pwm->fd == ASSUAN_INVALID_FD)
1478 return FINISH (GPG_ERR_INV_STATE);
1480 disconnect (pwm);
1481 reset_handle (pwm);
1482 return 0;
1485 /* Note that this should only be called when not in a command. */
1486 gpg_error_t
1487 pwmd_process (pwm_t * pwm)
1489 gpg_error_t rc = 0;
1490 fd_set fds;
1491 struct timeval tv = { 0, 0 };
1492 int n;
1494 if (!pwm || pwm->fd == ASSUAN_INVALID_FD)
1495 return FINISH (GPG_ERR_INV_ARG);
1496 else if (!pwm->ctx)
1497 return FINISH (GPG_ERR_INV_STATE);
1499 FD_ZERO (&fds);
1500 #ifdef __MINGW32__
1501 FD_SET (_get_osfhandle (pwm->fh), &fds);
1502 #else
1503 FD_SET (pwm->fd, &fds);
1504 #endif
1505 n = select (HANDLE2SOCKET (pwm->fd) + 1, &fds, NULL, NULL, &tv);
1507 if (n == -1)
1509 #ifdef _MINGW32__
1510 switch (WSAGetLastError ())
1512 case WSAENOTSOCK:
1513 gpg_err_set_errno (EBADF);
1514 break;
1515 case WSAEWOULDBLOCK:
1516 gpg_err_set_errno (EAGAIN);
1517 break;
1518 case WSAECONNRESET:
1519 case ERROR_BROKEN_PIPE:
1520 gpg_err_set_errno (EPIPE);
1521 break;
1522 default:
1523 gpg_err_set_errno (EIO);
1524 break;
1526 #endif
1527 return FINISH (gpg_error_from_syserror ());
1530 if (n > 0)
1532 if (FD_ISSET (HANDLE2SOCKET (pwm->fd), &fds))
1533 rc = parse_assuan_line (pwm);
1536 while (!rc && assuan_pending_line (pwm->ctx))
1537 rc = parse_assuan_line (pwm);
1539 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1540 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1542 __assuan_close (pwm->ctx, pwm->fd);
1543 pwm->fd = ASSUAN_INVALID_FD;
1545 #endif
1547 return FINISH (rc);
1550 static gpg_error_t
1551 status_cb (void *data, const char *line)
1553 pwm_t *pwm = data;
1555 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1556 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1557 else if (!strncmp (line, "BULK ", 5))
1559 pwmd_free (pwm->bulk_id);
1560 pwm->bulk_id = NULL;
1561 if (!strncmp (line+5, "BEGIN ", 6))
1563 pwm->bulk_id = pwmd_strdup (line+11);
1564 if (!pwm->bulk_id)
1565 return gpg_error (GPG_ERR_ENOMEM);
1567 else if (strncmp (line+5, "END ", 4))
1568 return gpg_error (GPG_ERR_UNEXPECTED_MSG);
1570 else if (!strncmp (line, "PASSPHRASE_HINT ", 16))
1572 pwmd_free (pwm->passphrase_hint);
1573 pwm->passphrase_hint = pwmd_strdup (line+16);
1575 else if (!strncmp (line, "PASSPHRASE_INFO ", 16))
1577 pwmd_free (pwm->passphrase_info);
1578 pwm->passphrase_info = pwmd_strdup (line+16);
1580 else if (!strcmp (line, "PIN_REPEATED"))
1581 pwm->pin_repeated = 1;
1582 else if (pwm->version >= 0x030101 && pwm->status_func
1583 && !strncmp (line, "XFER ", 5))
1585 /* Initial XFER sent from pwmd. Set's the total length of the data to be
1586 * received. */
1587 char *p = strchr (line, ' ');
1588 size_t a = strtoul (++p, NULL, 10);
1589 size_t b;
1590 char buf[ASSUAN_LINELENGTH];
1592 (void)a;
1594 while (isdigit (*p))
1595 p++;
1597 b = strtoul (++p, NULL, 10);
1598 pwm->data_total = b;
1599 snprintf (buf, sizeof (buf), "XFER %zu %zu", (size_t)0, pwm->data_total);
1600 return pwm->status_func (pwm->status_data, buf);
1602 #ifdef WITH_GNUTLS
1603 else if (!strcmp (line, "REHANDSHAKE"))
1605 char buf[32];
1606 ssize_t ret;
1608 ret = tls_read_hook (pwm, pwm->fd, buf, sizeof (buf));
1609 if (ret < 0)
1611 pwm->tls_error = ret;
1612 return GPG_ERR_GENERAL;
1615 #endif
1617 if (pwm->status_func)
1618 return pwm->status_func (pwm->status_data, line);
1620 return 0;
1623 gpg_error_t
1624 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1625 char **result, size_t * len, const char *cmd)
1627 membuf_t data;
1628 gpg_error_t rc;
1630 if (!cmd || !*cmd)
1631 return FINISH (GPG_ERR_INV_ARG);
1633 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1634 return FINISH (GPG_ERR_LINE_TOO_LONG);
1636 data.pwm = pwm;
1637 data.len = 0;
1638 data.buf = NULL;
1640 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1641 #if WITH_QUALITY && WITH_PINENTRY
1642 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1643 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1644 #else
1645 inquire_cb, pwm,
1646 #endif
1647 status_cb, pwm);
1649 if (rc)
1651 if (data.buf)
1653 pwmd_free (data.buf);
1654 data.buf = NULL;
1657 else
1659 if (data.buf)
1661 inquire_realloc_cb (&data, "", 1);
1663 if (result)
1664 *result = (char *) data.buf;
1665 else
1666 pwmd_free (data.buf);
1668 if (len)
1669 *len = data.len;
1673 pwm->inquire_maxlen = 0;
1674 return rc;
1677 gpg_error_t
1678 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1679 pwmd_inquire_cb_t func, void *user, const char *cmd,
1680 va_list ap)
1682 char *buf;
1683 size_t len;
1684 va_list ap2;
1686 if (!pwm)
1687 return GPG_ERR_INV_ARG;
1689 command_start (pwm);
1691 if (result)
1692 *result = NULL;
1694 if (rlen)
1695 *rlen = 0;
1697 if (!pwm || !cmd)
1698 return FINISH (GPG_ERR_INV_ARG);
1699 if (!pwm->ctx)
1700 return FINISH (GPG_ERR_INV_STATE);
1703 * C99 allows the dst pointer to be null which will calculate the length
1704 * of the would-be result and return it.
1706 va_copy (ap2, ap);
1707 len = vsnprintf (NULL, 0, cmd, ap);
1708 buf = (char *) pwmd_malloc (len+1);
1709 if (!buf)
1711 va_end (ap2);
1712 return FINISH (GPG_ERR_ENOMEM);
1715 if (vsnprintf (buf, len+1, cmd, ap2) != len)
1717 pwmd_free (buf);
1718 va_end (ap2);
1719 return FINISH (GPG_ERR_ENOMEM);
1722 va_end (ap2);
1723 if (buf[strlen (buf) - 1] == '\n')
1724 buf[strlen (buf) - 1] = 0;
1725 if (buf[strlen (buf) - 1] == '\r')
1726 buf[strlen (buf) - 1] = 0;
1728 pwm->inquire_func = func;
1729 pwm->inquire_data = user;
1730 pwm->inquire_sent = 0;
1731 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1732 pwmd_free (buf);
1733 return rc;
1736 gpg_error_t
1737 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1738 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1740 va_list ap;
1742 if (result)
1743 *result = NULL;
1745 if (len)
1746 *len = 0;
1748 if (!pwm || !cmd)
1749 return FINISH (GPG_ERR_INV_ARG);
1750 if (!pwm->ctx)
1751 return FINISH (GPG_ERR_INV_STATE);
1753 va_start (ap, cmd);
1754 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1755 va_end (ap);
1756 return rc;
1759 gpg_error_t
1760 pwmd_bulk (pwm_t *pwm, char **result, size_t *size, pwmd_inquire_cb_t func,
1761 void *user, const char *cmds, size_t len)
1763 gpg_error_t rc;
1764 struct bulk_inquire_s *inq;
1766 if (!pwm)
1767 return GPG_ERR_INV_ARG;
1769 if (!pwm->ctx)
1770 return FINISH (GPG_ERR_INV_STATE);
1772 if (result)
1773 *result = NULL;
1775 if (size)
1776 *size = 0;
1778 inq = pwmd_calloc (1, sizeof (struct bulk_inquire_s));
1779 if (!inq)
1780 return FINISH (GPG_ERR_ENOMEM);
1782 command_start (pwm);
1783 inq->pwm = pwm;
1784 inq->user = user;
1785 inq->func = func;
1786 inq->data = cmds;
1787 inq->size = len;
1788 pwm->inquire_func = bulk_inquire_cb;
1789 pwm->inquire_data = inq;
1790 pwm->inquire_sent = 0;
1791 rc = _assuan_command (pwm, pwm->ctx, result, size, "BULK --inquire");
1792 pwmd_free (pwm->bulk_id);
1793 pwm->bulk_id = NULL;
1794 pwmd_free (inq);
1795 return FINISH (rc);
1798 static gpg_error_t
1799 set_pinentry_options (pwm_t * pwm, int which, char **cmds, size_t *offset)
1801 gpg_error_t rc;
1802 char *str = NULL;
1803 gpg_error_t rcs[] = { 0, GPG_ERR_MISSING_ERRNO };
1805 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_ENABLE", strlen ("PIN_ENABLE"),
1806 "OPTION", "disable-pinentry=0", 18, offset);
1808 if (!rc && pwm->pinentry_tty)
1810 str = pwmd_strdup_printf ("TTYNAME=%s", pwm->pinentry_tty);
1811 (*offset)--;
1812 if (str)
1813 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_TTY", strlen ("PIN_TTY"),
1814 "OPTION", str, strlen (str), offset);
1815 else
1816 rc = GPG_ERR_ENOMEM;
1818 pwmd_free (str);
1821 if (!rc && pwm->pinentry_term)
1823 str = pwmd_strdup_printf ("TTYTYPE=%s", pwm->pinentry_term);
1824 (*offset)--;
1825 if (str)
1826 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_TERM", strlen ("PIN_TERM"),
1827 "OPTION", str, strlen (str), offset);
1828 else
1829 rc = GPG_ERR_ENOMEM;
1831 pwmd_free (str);
1834 if (!rc && pwm->pinentry_display)
1836 str = pwmd_strdup_printf ("DISPLAY=%s", pwm->pinentry_display);
1837 (*offset)--;
1838 if (str)
1839 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_DISPLAY",
1840 strlen ("PIN_DISPLAY"), "OPTION", str,
1841 strlen (str), offset);
1842 else
1843 rc = GPG_ERR_ENOMEM;
1845 pwmd_free (str);
1848 if (!rc && pwm->pinentry_desc)
1850 str = pwmd_strdup_printf ("DESC=%s", pwm->pinentry_desc);
1851 (*offset)--;
1852 if (str)
1853 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_DESC", strlen ("PIN_DESC"),
1854 "OPTION", str, strlen (str), offset);
1855 else
1856 rc = GPG_ERR_ENOMEM;
1858 pwmd_free (str);
1861 if (!rc && pwm->pinentry_lcctype)
1863 str = pwmd_strdup_printf ("LC_CTYPE=%s", pwm->pinentry_lcctype);
1864 (*offset)--;
1865 if (str)
1866 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_LCCTYPE",
1867 strlen ("PIN_LCCTYPE"), "OPTION", str,
1868 strlen (str), offset);
1869 else
1870 rc = GPG_ERR_ENOMEM;
1872 pwmd_free (str);
1875 if (!rc && pwm->pinentry_lcmessages)
1877 str = pwmd_strdup_printf ("LC_MESSAGES=%s", pwm->pinentry_lcmessages);
1878 (*offset)--;
1879 if (str)
1880 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_LCMESSAGES",
1881 strlen ("PIN_LCMESSAGES"), "OPTION", str,
1882 strlen (str), offset);
1883 else
1884 rc = GPG_ERR_ENOMEM;
1886 pwmd_free (str);
1889 if (!rc && ((pwm->pinentry_timeout >= 0
1890 && pwm->pinentry_timeout != pwm->current_pinentry_timeout)
1891 || (pwm->pinentry_timeout == -1 && pwm->pinentry_timeout !=
1892 pwm->current_pinentry_timeout)))
1894 str = pwmd_strdup_printf ("pinentry-timeout=%i", pwm->pinentry_timeout);
1895 (*offset)--;
1896 if (str)
1897 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_TIMEOUT",
1898 strlen ("PIN_TIMEOUT"), "OPTION", str,
1899 strlen (str), offset);
1900 else
1901 rc = GPG_ERR_ENOMEM;
1903 pwmd_free (str);
1904 if (!rc)
1905 pwm->current_pinentry_timeout = pwm->pinentry_timeout;
1908 return rc;
1911 gpg_error_t
1912 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1914 if (!pwm || !result)
1915 return FINISH (GPG_ERR_INV_ARG);
1917 *result = PWMD_SOCKET_LOCAL;
1919 if (pwm->fd == ASSUAN_INVALID_FD)
1920 return FINISH (GPG_ERR_INV_STATE);
1922 if (pwm->user_fd != -1)
1924 *result = PWMD_SOCKET_USER;
1925 return 0;
1928 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1929 #ifdef WITH_SSH
1930 if (pwm->tcp && pwm->tcp->ssh)
1931 *result = PWMD_SOCKET_SSH;
1932 #endif
1933 #ifdef WITH_GNUTLS
1934 if (pwm->tcp && pwm->tcp->tls)
1935 *result = PWMD_SOCKET_TLS;
1936 #endif
1937 #endif
1938 return 0;
1941 static gpg_error_t
1942 disable_pinentry (pwm_t *pwm, int *disable, char **cmds, size_t *offset,
1943 int force)
1945 gpg_error_t rc;
1946 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1947 int no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1948 #else
1949 int no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1950 #endif
1951 char *buf;
1952 gpg_error_t rcs[] = { 0, GPG_ERR_MISSING_ERRNO };
1954 if (force != -1)
1955 no_pinentry = !!force;
1957 if (disable)
1958 *disable = no_pinentry;
1960 if (force == -1 && pwm->pinentry_disabled && no_pinentry)
1961 return 0;
1962 else if (force == -1 && !pwm->pinentry_disabled && !no_pinentry)
1963 return 0;
1965 buf = pwmd_strdup_printf ("disable-pinentry=%i", no_pinentry);
1966 if (buf && force == -1)
1967 rc = pwmd_bulk_append_rc (cmds, rcs, "PIN_ENABLE", strlen ("PIN_ENABLE"),
1968 "OPTION", buf, strlen (buf), offset);
1969 else if (buf)
1970 rc = pwmd_bulk_append (cmds, "PIN_ENABLE", strlen ("PIN_ENABLE"),
1971 "OPTION", buf, strlen (buf), NULL);
1972 else
1973 rc = GPG_ERR_ENOMEM;
1975 pwmd_free (buf);
1976 return rc;
1979 static gpg_error_t
1980 parse_pinentry_results (pwm_t *pwm, const char *result, size_t size,
1981 size_t *offset, int no_pinentry)
1983 gpg_error_t rc, rrc = 0;
1984 size_t rsize;
1985 const char *r;
1987 rc = pwmd_bulk_result (result, size, "PIN_ENABLE", 10, offset, &r, &rsize,
1988 &rrc);
1989 if (!rc && !rrc)
1990 pwm->pinentry_disabled = no_pinentry;
1992 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
1993 rc = pwmd_bulk_result (result, size, "PIN_TTY", 7, offset, &r, &rsize,
1994 &rrc);
1996 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
1997 rc = pwmd_bulk_result (result, size, "PIN_TERM", 8, offset, &r, &rsize,
1998 &rrc);
2000 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
2001 rc = pwmd_bulk_result (result, size, "PIN_DISPLAY", 11, offset, &r, &rsize,
2002 &rrc);
2004 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
2005 rc = pwmd_bulk_result (result, size, "PIN_DESC", 8, offset, &r, &rsize,
2006 &rrc);
2008 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
2009 rc = pwmd_bulk_result (result, size, "PIN_LCCTYPE", 11, offset, &r, &rsize,
2010 &rrc);
2012 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
2013 rc = pwmd_bulk_result (result, size, "PIN_LCMESSAGES", 14, offset, &r,
2014 &rsize, &rrc);
2016 if (!rrc && (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND))
2017 rc = pwmd_bulk_result (result, size, "PIN_TIMEOUT", 11, offset, &r, &rsize,
2018 &rrc);
2020 if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
2021 rc = 0;
2023 return rc ? rc : rrc;
2026 gpg_error_t
2027 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
2028 void *data)
2030 gpg_error_t rc = 0;
2031 int no_pinentry = 0;
2032 char *cmds = NULL;
2033 size_t offset = 0, toffset;
2034 gpg_error_t rcs[] = { 0, GPG_ERR_MISSING_ERRNO };
2036 if (!pwm || !filename || !*filename)
2037 return FINISH (GPG_ERR_INV_ARG);
2039 if (!pwm->ctx)
2040 return FINISH (GPG_ERR_INV_STATE);
2042 // A dummy command to deal with pwmd_bulk_append_rc().
2043 rc = pwmd_bulk_append (&cmds, "NOP", 3, "NOP", NULL, 0, &offset);
2044 if (rc)
2045 return FINISH (rc);
2047 toffset = offset;
2048 command_start (pwm);
2049 rc = disable_pinentry (pwm, &no_pinentry, &cmds, &offset, -1);
2050 if (!rc && !no_pinentry)
2052 TEST_BULK_OFFSET (offset, toffset);
2053 rc = set_pinentry_options (pwm, PWMD_WHICH_NONE, &cmds, &offset);
2056 if (!rc)
2058 char *buf;
2060 pwm->pinentry_try = 0;
2061 pwmd_free (pwm->filename);
2062 pwm->filename = pwmd_strdup (filename);
2064 if (pwm->lock_timeout != -2)
2066 buf = pwmd_strdup_printf ("lock-timeout=%li", pwm->lock_timeout);
2067 if (buf)
2069 TEST_BULK_OFFSET (offset, toffset);
2070 rc = pwmd_bulk_append_rc (&cmds, rcs, "LOCK_TO",
2071 strlen ("LOCK_TO"), "OPTION", buf,
2072 strlen (buf), &offset);
2074 else
2075 rc = GPG_ERR_ENOMEM;
2077 pwmd_free (buf);
2080 if (!rc)
2081 buf = pwmd_strdup_printf ("%s%s", (pwm->opts & OPT_LOCK_ON_OPEN)
2082 ? "--lock " : "", filename);
2083 if (!rc && buf)
2085 TEST_BULK_OFFSET (offset, toffset);
2086 rc = pwmd_bulk_append_rc (&cmds, rcs, "OPEN", strlen ("OPEN"),
2087 "OPEN", buf, strlen (buf), &offset);
2089 else if (!rc)
2090 rc = GPG_ERR_ENOMEM;
2092 pwmd_free (buf);
2093 if (!rc)
2095 rc = disable_pinentry (pwm, &no_pinentry, &cmds, &offset, 0);
2096 if (!rc)
2097 rc = pwmd_bulk_finalize (&cmds);
2100 if (!rc)
2102 char *result;
2103 size_t size;
2105 rc = pwmd_bulk (pwm, &result, &size, cb, data, cmds, strlen (cmds));
2106 pwmd_free (cmds);
2107 cmds = NULL;
2108 if (!rc)
2110 const char *r;
2111 gpg_error_t rrc = 0;
2112 size_t rsize;
2114 offset = 0;
2115 rc = parse_pinentry_results (pwm, result, size, &offset,
2116 no_pinentry);
2118 if (!rc || gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
2119 rc = pwmd_bulk_result (result, size, "LOCK_TO", 7, &offset, &r,
2120 &rsize, &rrc);
2122 if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
2123 rc = 0;
2125 if (!rc)
2126 rc = rrc;
2128 if (!rc)
2129 rc = pwmd_bulk_result (result, size, "OPEN", 4, &offset, &r,
2130 &rsize, &rrc);
2132 if (!rc)
2133 rc = rrc;
2135 pwmd_free (result);
2136 while ((gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
2137 || gpg_err_code (rc) == GPG_ERR_DECRYPT_FAILED)
2138 && pwm->pinentry_disabled
2139 && ++pwm->pinentry_try < pwm->pinentry_tries)
2141 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
2142 (pwm->opts & OPT_LOCK_ON_OPEN)
2143 ? "--lock " : "", filename);
2148 pwm->pinentry_try = 0;
2149 pwm->pinentry_disabled = 0;
2151 if (rc)
2153 pwmd_free (pwm->filename);
2154 pwm->filename = NULL;
2158 pwmd_free (cmds);
2159 pwmd_free (pwm->passphrase_hint);
2160 pwmd_free (pwm->passphrase_info);
2161 pwm->passphrase_info = pwm->passphrase_hint = NULL;
2162 return FINISH (rc);
2165 static gpg_error_t
2166 do_pwmd_save_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb,
2167 void *data, int which)
2169 gpg_error_t rc = 0;
2170 int no_pinentry = 0;
2171 char *cmds = NULL;
2172 size_t offset = 0, toffset;
2173 gpg_error_t rcs[] = { 0, GPG_ERR_MISSING_ERRNO };
2175 if (!pwm)
2176 return FINISH (GPG_ERR_INV_ARG);
2177 if (!pwm->ctx)
2178 return FINISH (GPG_ERR_INV_STATE);
2180 // A dummy command to deal with pwmd_bulk_append_rc().
2181 rc = pwmd_bulk_append (&cmds, "NOP", 3, "NOP", NULL, 0, &offset);
2182 if (rc)
2183 return FINISH (rc);
2185 toffset = offset;
2186 command_start (pwm);
2187 rc = disable_pinentry (pwm, &no_pinentry, &cmds, &offset, -1);
2188 if (!rc && !no_pinentry)
2190 TEST_BULK_OFFSET (offset, toffset);
2191 rc = set_pinentry_options (pwm, which, &cmds, &offset);
2194 if (!rc)
2196 char *buf;
2197 const char *p;
2199 buf = pwmd_strdup_printf ("%s", args ? args : "");
2201 if (which == PWMD_WHICH_SAVE)
2202 p = "SAVE";
2203 else if (which == PWMD_WHICH_PASSWD)
2204 p = "PASSWD";
2205 else
2206 p = "GENKEY";
2208 TEST_BULK_OFFSET (offset, toffset);
2209 if (buf)
2210 rc = pwmd_bulk_append_rc (&cmds, rcs, p, strlen (p), p, buf,
2211 strlen (buf), &offset);
2212 else
2213 rc = GPG_ERR_ENOMEM;
2215 if (!rc)
2216 rc = disable_pinentry (pwm, &no_pinentry, &cmds, &offset, 0);
2218 if (!rc)
2219 rc = pwmd_bulk_finalize (&cmds);
2221 pwmd_free (buf);
2223 if (!rc)
2225 char *result;
2226 size_t size;
2228 rc = pwmd_bulk (pwm, &result, &size, cb, data, cmds, strlen (cmds));
2229 pwmd_free (cmds);
2230 cmds = NULL;
2231 if (!rc)
2233 const char *r;
2234 gpg_error_t rrc = 0;
2235 size_t rsize;
2237 offset = 0;
2238 rc = parse_pinentry_results (pwm, result, size, &offset,
2239 no_pinentry);
2241 if (!rc)
2242 rc = pwmd_bulk_result (result, size, p, strlen (p), &offset,
2243 &r, &rsize, &rrc);
2244 if (!rc)
2245 rc = rrc;
2247 pwmd_free (result);
2252 pwm->disable_pinentry = 0;
2253 pwmd_free (cmds);
2254 pwmd_free (pwm->passphrase_hint);
2255 pwmd_free (pwm->passphrase_info);
2256 pwm->passphrase_info = pwm->passphrase_hint = NULL;
2257 return FINISH (rc);
2260 gpg_error_t
2261 pwmd_passwd (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
2263 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_PASSWD);
2266 gpg_error_t
2267 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
2269 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_SAVE);
2272 gpg_error_t
2273 pwmd_genkey (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
2275 return do_pwmd_save_passwd (pwm, args, cb, data, PWMD_WHICH_GENKEY);
2278 static gpg_error_t
2279 pwmd_get_set_opt (pwm_t *pwm, pwmd_option_t opt, int get, va_list ap)
2281 long l, *longp;
2282 int n, *intp;
2283 size_t *sizetp;
2284 char *arg1, **charpp;
2285 gpg_error_t rc = 0;
2287 if (!pwm)
2288 return GPG_ERR_INV_ARG;
2290 command_start (pwm);
2291 switch (opt)
2293 case PWMD_OPTION_SERVER_VERSION:
2294 if (!get)
2295 return GPG_ERR_NOT_SUPPORTED;
2297 if (!pwm->ctx)
2298 rc = GPG_ERR_INV_STATE;
2299 else
2301 unsigned *u = va_arg (ap, unsigned *);
2302 *u = pwm->version;
2305 break;
2306 case PWMD_OPTION_SIGPIPE:
2307 if (get)
2309 intp = va_arg (ap, int *);
2310 *intp = pwm->opts & OPT_SIGPIPE ? 1 : 0;
2311 break;
2314 n = va_arg (ap, int);
2315 if (n < 0 || n > 1)
2317 rc = GPG_ERR_INV_VALUE;
2318 break;
2321 if (n)
2322 pwm->opts |= OPT_SIGPIPE;
2323 else
2324 pwm->opts &= ~OPT_SIGPIPE;
2326 break;
2327 case PWMD_OPTION_STATE_STATUS:
2328 if (get)
2330 intp = va_arg (ap, int *);
2331 *intp = pwm->opts & OPT_STATE_STATUS ? 1 : 0;
2332 break;
2335 n = va_arg (ap, int);
2336 if (n < 0 || n > 1)
2338 rc = GPG_ERR_INV_VALUE;
2339 break;
2342 if (n)
2343 pwm->opts |= OPT_STATE_STATUS;
2344 else
2345 pwm->opts &= ~OPT_STATE_STATUS;
2347 break;
2348 case PWMD_OPTION_LOCK_ON_OPEN:
2349 if (get)
2351 intp = va_arg (ap, int *);
2352 *intp = pwm->opts & OPT_LOCK_ON_OPEN ? 1 : 0;
2353 break;
2356 n = va_arg (ap, int);
2357 if (n < 0 || n > 1)
2359 rc = GPG_ERR_INV_VALUE;
2360 break;
2363 if (n)
2364 pwm->opts |= OPT_LOCK_ON_OPEN;
2365 else
2366 pwm->opts &= ~OPT_LOCK_ON_OPEN;
2368 break;
2369 case PWMD_OPTION_LOCK_TIMEOUT:
2370 if (get)
2372 longp = va_arg (ap, long *);
2373 *longp = pwm->lock_timeout;
2374 break;
2377 l = va_arg (ap, long);
2378 if (l < -1)
2380 rc = GPG_ERR_INV_VALUE;
2381 break;
2384 pwm->lock_timeout = l;
2385 break;
2386 case PWMD_OPTION_INQUIRE_TOTAL:
2387 if (get)
2389 sizetp = va_arg (ap, size_t *);
2390 *sizetp = pwm->inquire_total;
2391 break;
2394 pwm->inquire_total = va_arg (ap, size_t);
2395 break;
2396 case PWMD_OPTION_STATUS_CB:
2397 if (get)
2399 pwmd_status_cb_t *cb = va_arg (ap, pwmd_status_cb_t *);
2401 *cb = pwm->status_func;
2402 break;
2405 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
2406 break;
2407 case PWMD_OPTION_STATUS_DATA:
2408 if (get)
2410 void **data = va_arg (ap, void **);
2412 *data = pwm->status_data;
2413 break;
2416 pwm->status_data = va_arg (ap, void *);
2417 break;
2418 case PWMD_OPTION_NO_PINENTRY:
2419 if (get)
2421 intp = va_arg (ap, int *);
2422 *intp = pwm->disable_pinentry;
2423 break;
2426 n = va_arg (ap, int);
2427 if (n < 0 || n > 1)
2428 rc = GPG_ERR_INV_VALUE;
2429 else
2430 pwm->disable_pinentry = n;
2431 break;
2432 case PWMD_OPTION_LOCAL_PINENTRY:
2433 if (get)
2435 intp = va_arg (ap, int *);
2436 *intp = pwm->local_pinentry;
2437 break;
2440 n = va_arg (ap, int);
2441 if (n < 0 || n > 1)
2442 rc = GPG_ERR_INV_VALUE;
2443 else
2444 pwm->local_pinentry = n;
2446 break;
2447 case PWMD_OPTION_PINENTRY_TIMEOUT:
2448 if (get)
2450 intp = va_arg (ap, int *);
2451 *intp = pwm->pinentry_timeout;
2452 break;
2455 n = va_arg (ap, int);
2456 if (n < 0)
2457 rc = GPG_ERR_INV_VALUE;
2458 else
2459 pwm->pinentry_timeout = n;
2460 break;
2461 case PWMD_OPTION_PINENTRY_TRIES:
2462 if (get)
2464 intp = va_arg (ap, int *);
2465 *intp = pwm->pinentry_tries;
2466 break;
2469 n = va_arg (ap, int);
2470 if (n < 0)
2471 rc = GPG_ERR_INV_VALUE;
2472 else
2473 pwm->pinentry_tries = n;
2474 break;
2475 case PWMD_OPTION_PINENTRY_PATH:
2476 if (get)
2478 charpp = va_arg (ap, char **);
2479 *charpp = (char *)PINENTRY_PATH;
2480 break;
2482 break;
2483 case PWMD_OPTION_PINENTRY_TTY:
2484 if (get)
2486 charpp = va_arg (ap, char **);
2487 *charpp = pwm->pinentry_tty;
2488 break;
2491 arg1 = va_arg (ap, char *);
2492 pwmd_free (pwm->pinentry_tty);
2493 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
2494 break;
2495 case PWMD_OPTION_PINENTRY_DISPLAY:
2496 if (get)
2498 charpp = va_arg (ap, char **);
2499 *charpp = pwm->pinentry_display;
2500 break;
2503 arg1 = va_arg (ap, char *);
2504 pwmd_free (pwm->pinentry_display);
2505 pwm->pinentry_display = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
2506 #ifndef __MINGW32__
2507 if (!pwm->pinentry_display)
2508 unsetenv ("DISPLAY");
2509 #endif
2510 break;
2511 case PWMD_OPTION_PINENTRY_TERM:
2512 if (get)
2514 charpp = va_arg (ap, char **);
2515 *charpp = pwm->pinentry_term;
2516 break;
2519 arg1 = va_arg (ap, char *);
2520 pwmd_free (pwm->pinentry_term);
2521 pwm->pinentry_term = arg1 && *arg1 ? pwmd_strdup (arg1) : NULL;
2522 #ifndef __MINGW32__
2523 if (pwm->pinentry_term)
2524 unsetenv ("TERM");
2525 #endif
2526 break;
2527 case PWMD_OPTION_PINENTRY_ERROR:
2528 if (get)
2530 charpp = va_arg (ap, char **);
2531 *charpp = pwm->pinentry_error;
2532 break;
2535 arg1 = va_arg (ap, char *);
2536 pwmd_free (pwm->pinentry_error);
2537 if (pwm->disable_pinentry)
2538 pwm->pinentry_error = arg1 ? pwmd_strdup (arg1) : NULL;
2539 else
2540 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
2541 break;
2542 case PWMD_OPTION_PINENTRY_PROMPT:
2543 if (get)
2545 charpp = va_arg (ap, char **);
2546 *charpp = pwm->pinentry_prompt;
2547 break;
2550 arg1 = va_arg (ap, char *);
2551 pwmd_free (pwm->pinentry_prompt);
2552 if (pwm->disable_pinentry)
2553 pwm->pinentry_prompt = arg1 ? pwmd_strdup (arg1) : NULL;
2554 else
2555 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
2556 break;
2557 case PWMD_OPTION_PINENTRY_DESC:
2558 if (get)
2560 charpp = va_arg (ap, char **);
2561 *charpp = pwm->pinentry_desc;
2562 break;
2565 arg1 = va_arg (ap, char *);
2566 pwmd_free (pwm->pinentry_desc);
2567 if (pwm->disable_pinentry)
2568 pwm->pinentry_desc = arg1 ? pwmd_strdup (arg1) : NULL;
2569 else
2570 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
2571 break;
2572 case PWMD_OPTION_PINENTRY_LC_CTYPE:
2573 if (get)
2575 charpp = va_arg (ap, char **);
2576 *charpp = pwm->pinentry_lcctype;
2577 break;
2580 arg1 = va_arg (ap, char *);
2581 pwmd_free (pwm->pinentry_lcctype);
2582 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
2583 break;
2584 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
2585 if (get)
2587 charpp = va_arg (ap, char **);
2588 *charpp = pwm->pinentry_lcmessages;
2589 break;
2592 arg1 = va_arg (ap, char *);
2593 pwmd_free (pwm->pinentry_lcmessages);
2594 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
2595 break;
2596 case PWMD_OPTION_KNOWNHOST_CB:
2597 if (get)
2599 pwmd_knownhost_cb_t *cb = va_arg (ap, pwmd_knownhost_cb_t *);
2601 *cb = pwm->kh_cb;
2602 break;
2605 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
2606 break;
2607 case PWMD_OPTION_KNOWNHOST_DATA:
2608 if (get)
2610 void **data = va_arg (ap, void **);
2612 *data = pwm->kh_data;
2613 break;
2616 pwm->kh_data = va_arg (ap, void *);
2617 break;
2618 case PWMD_OPTION_PASSPHRASE_CB:
2619 if (get)
2621 pwmd_passphrase_cb_t *cb = va_arg (ap, pwmd_passphrase_cb_t *);
2623 *cb = pwm->passphrase_cb;
2624 break;
2627 pwm->passphrase_cb = va_arg (ap, pwmd_passphrase_cb_t);
2628 break;
2629 case PWMD_OPTION_PASSPHRASE_DATA:
2630 if (get)
2632 void **data = va_arg (ap, void **);
2634 *data = pwm->passphrase_data;
2635 break;
2638 pwm->passphrase_data = va_arg (ap, void *);
2639 break;
2640 case PWMD_OPTION_SSH_AGENT:
2641 if (get)
2643 intp = va_arg (ap, int *);
2644 *intp = pwm->use_agent;
2645 break;
2648 n = va_arg (ap, int);
2649 if (n < 0 || n > 1)
2650 rc = GPG_ERR_INV_VALUE;
2651 else
2652 pwm->use_agent = n;
2653 break;
2654 case PWMD_OPTION_SSH_PASSPHRASE:
2655 if (get)
2656 return GPG_ERR_NOT_SUPPORTED;
2658 pwmd_free (pwm->ssh_passphrase);
2659 pwm->ssh_passphrase = NULL;
2660 arg1 = va_arg (ap, char *);
2661 if (arg1)
2663 pwm->ssh_passphrase = pwmd_strdup (arg1);
2664 if (!pwm->ssh_passphrase)
2665 return GPG_ERR_ENOMEM;
2667 break;
2668 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE:
2669 if (get)
2671 intp = va_arg (ap, int *);
2672 *intp = pwm->needs_passphrase;
2673 break;
2676 n = va_arg (ap, int);
2677 if (n < 0 || n > 1)
2678 rc = GPG_ERR_INV_VALUE;
2679 else
2680 pwm->needs_passphrase = n;
2681 break;
2682 case PWMD_OPTION_TLS_VERIFY:
2683 if (get)
2685 intp = va_arg (ap, int *);
2686 *intp = pwm->tls_verify;
2687 break;
2690 n = va_arg (ap, int);
2691 if (n < 0 || n > 1)
2692 rc = GPG_ERR_INV_VALUE;
2693 else
2694 pwm->tls_verify = n;
2695 break;
2696 case PWMD_OPTION_TLS_PRIORITY:
2697 if (get)
2699 charpp = va_arg (ap, char **);
2700 *charpp = pwm->tls_priority;
2701 break;
2704 pwmd_free (pwm->tls_priority);
2705 pwm->tls_priority = NULL;
2706 arg1 = va_arg (ap, char *);
2707 if (arg1)
2709 pwm->tls_priority = pwmd_strdup (arg1);
2710 if (!pwm->tls_priority)
2711 rc = GPG_ERR_ENOMEM;
2713 break;
2714 case PWMD_OPTION_SOCKET_TIMEOUT:
2715 if (get)
2717 intp = va_arg (ap, int *);
2718 *intp = pwm->socket_timeout;
2719 break;
2722 n = va_arg (ap, int);
2723 if (n < 0)
2725 rc = GPG_ERR_INV_VALUE;
2726 break;
2728 else
2729 pwm->socket_timeout = n;
2731 #ifdef WITH_SSH
2732 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
2734 pwm->tcp->ssh->timeout = pwm->socket_timeout;
2735 libssh2_session_set_timeout (pwm->tcp->ssh->session,
2736 pwm->socket_timeout * 1000);
2738 #endif
2739 #ifdef WITH_GNUTLS
2740 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
2741 pwm->tcp->tls->timeout = pwm->socket_timeout;
2742 #endif
2743 break;
2744 case PWMD_OPTION_READ_CB:
2745 if (get)
2747 pwmd_read_cb_t *cb = va_arg (ap, pwmd_read_cb_t *);
2749 *cb = pwm->read_cb;
2750 break;
2752 pwm->read_cb = va_arg (ap, pwmd_read_cb_t);
2753 break;
2754 case PWMD_OPTION_READ_CB_DATA:
2755 if (get)
2757 void **data = va_arg (ap, void **);
2759 *data = pwm->read_cb_data;
2760 break;
2763 pwm->read_cb_data = va_arg (ap, void *);
2764 break;
2765 case PWMD_OPTION_WRITE_CB:
2766 if (get)
2768 pwmd_write_cb_t *cb = va_arg (ap, pwmd_write_cb_t *);
2770 *cb = pwm->write_cb;
2771 break;
2773 pwm->write_cb = va_arg (ap, pwmd_write_cb_t);
2774 break;
2775 case PWMD_OPTION_WRITE_CB_DATA:
2776 if (get)
2778 void **data = va_arg (ap, void **);
2780 *data = pwm->write_cb_data;
2781 break;
2784 pwm->write_cb_data = va_arg (ap, void *);
2785 break;
2786 case PWMD_OPTION_OVERRIDE_INQUIRE:
2787 if (get)
2789 intp = va_arg (ap, int *);
2790 *intp = pwm->override_inquire;
2791 break;
2794 n = va_arg (ap, int);
2795 if (n < 0 || n > 1)
2796 rc = GPG_ERR_INV_VALUE;
2797 else
2798 pwm->override_inquire = n;
2799 break;
2800 default:
2801 rc = GPG_ERR_UNKNOWN_OPTION;
2802 break;
2805 return FINISH (rc);
2808 gpg_error_t
2809 pwmd_setopt (pwm_t * pwm, int opt, ...)
2811 va_list ap;
2812 gpg_error_t rc = 0;
2814 va_start (ap, opt);
2815 rc = pwmd_get_set_opt (pwm, opt, 0, ap);
2816 va_end (ap);
2817 return FINISH (rc);
2820 gpg_error_t
2821 pwmd_getopt (pwm_t *pwm, int opt, ...)
2823 va_list ap;
2824 gpg_error_t rc = 0;
2826 va_start (ap, opt);
2827 rc = pwmd_get_set_opt (pwm, opt, 1, ap);
2828 va_end (ap);
2829 return FINISH (rc);
2832 gpg_error_t
2833 set_rcdefaults (pwm_t *pwm, char *filename)
2835 char *f;
2836 FILE *fp;
2837 char *line = NULL, *p;
2838 unsigned line_n = 0;
2839 gpg_error_t rc = 0;
2841 #ifndef __MINGW32__
2842 if (!filename && isatty (STDIN_FILENO))
2844 char buf[256];
2845 int err = ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
2847 if (!err)
2849 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, buf);
2850 if (rc)
2851 return rc;
2853 if (getenv ("TERM"))
2855 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, getenv ("TERM"));
2856 if (rc)
2857 return rc;
2862 if (!filename && getenv ("DISPLAY"))
2864 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, getenv ("DISPLAY"));
2865 if (rc)
2866 return rc;
2868 #endif
2870 #ifdef __MINGW32__
2871 f = pwmd_strdup ("libpwmd.conf");
2872 #else
2873 f = _expand_homedir (filename ? filename : (char *)"~/.config/libpwmd.conf",
2874 NULL);
2875 #endif
2876 if (f)
2878 line = pwmd_malloc (LINE_MAX);
2879 if (line)
2881 fp = fopen (f, "r");
2882 if (!fp)
2884 pwmd_free (line);
2885 pwmd_free (f);
2886 return 0;
2889 else
2890 rc = GPG_ERR_ENOMEM;
2892 else
2893 rc = GPG_ERR_ENOMEM;
2895 if (rc)
2897 pwmd_free (f);
2898 pwmd_free (line);
2899 return rc;
2902 while ((p = fgets (line, LINE_MAX, fp)))
2904 char name[32] = {0}, val[512] = {0};
2905 char *np;
2906 char *t;
2907 size_t len = 0;
2909 line_n++;
2911 while (isspace (*p))
2912 p++;
2914 if (!*p || *p == '#')
2915 continue;
2917 if (p[strlen (p)-1] == '\n')
2918 p[strlen (p)-1] = 0;
2920 t = strchr (p, '=');
2921 if (!t)
2923 fprintf(stderr, N_("%s(%u): malformed line\n"), f, line_n);
2924 continue;
2927 for (np = name; p != t; p++)
2929 if (++len == sizeof (name))
2930 break;
2932 if (isspace (*p))
2933 break;
2935 *np++ = *p;
2938 while (isspace (*t))
2939 t++;
2940 t++; // '='
2941 while (isspace (*t))
2942 t++;
2944 strncpy (val, t, sizeof (val)-1);
2946 if (!strcasecmp (name, "pinentry-tries"))
2947 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, atoi (val));
2948 else if (!strcasecmp (name, "pinentry-timeout"))
2949 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, atoi (val));
2950 else if (!strcasecmp (name, "no-pinentry"))
2951 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, !!(atoi (val)));
2952 else if (!strcasecmp (name, "local-pinentry"))
2953 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, !!(atoi (val)));
2954 else if (!strcasecmp (name, "pinentry-display"))
2955 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, val);
2956 else if (!strcasecmp (name, "pinentry-ttyname"))
2957 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, val);
2958 else if (!strcasecmp (name, "pinentry-ttytype"))
2959 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, val);
2960 else if (!strcasecmp (name, "pinentry-lc-messages"))
2961 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, val);
2962 else if (!strcasecmp (name, "pinentry-lc-ctype"))
2963 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, val);
2964 else if (!strcasecmp (name, "no-ssh-agent"))
2965 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, !(atoi (val)));
2966 else if (!strcasecmp (name, "no-tls-verify"))
2967 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, !(atoi (val)));
2968 else if (!strcasecmp (name, "tls-priority"))
2969 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, val);
2970 else if (!strcasecmp (name, "socket-timeout"))
2971 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, atoi (val));
2972 else if (!strcasecmp (name, "lock-timeout"))
2973 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_TIMEOUT, strtol (val, NULL, 10));
2974 else if (!strcasecmp (name, "no-lock"))
2975 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, !(atoi (val)));
2976 else if (!strcasecmp (name, "include"))
2977 rc = set_rcdefaults (pwm, val);
2978 else
2979 fprintf(stderr, N_("%s(%u): invalid option '%s', ignored.\n"), f,
2980 line_n, name);
2982 if (rc)
2983 break;
2986 fclose (fp);
2987 pwmd_free (line);
2988 pwmd_free (f);
2989 return rc;
2992 gpg_error_t
2993 pwmd_new (const char *name, pwm_t ** pwm)
2995 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
2996 gpg_error_t rc;
2998 if (!h)
2999 return FINISH (GPG_ERR_ENOMEM);
3001 if (name)
3003 h->name = pwmd_strdup (name);
3004 if (!h->name)
3006 pwmd_free (h);
3007 return FINISH (GPG_ERR_ENOMEM);
3011 reset_handle (h);
3012 h->use_agent = -1;
3013 h->pinentry_timeout = -1;
3014 h->current_pinentry_timeout = -1;
3015 h->pinentry_tries = 3;
3016 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
3017 h->prot = PWMD_IP_ANY;
3018 h->socket_timeout = 120;
3019 h->tls_verify = 1;
3020 #ifdef __MINGW32__
3021 WSADATA wsdata;
3023 WSAStartup (0x202, &wsdata);
3024 #endif
3026 #endif
3027 h->opts |= OPT_LOCK_ON_OPEN;
3029 rc = set_rcdefaults (h, NULL);
3030 if (rc)
3031 goto fail;
3033 *pwm = h;
3034 return 0;
3036 fail:
3037 pwmd_close (h);
3038 return FINISH (rc);
3041 void
3042 pwmd_free (void *ptr)
3044 _xfree (ptr);
3047 void *
3048 pwmd_malloc (size_t size)
3050 return _xmalloc (size);
3053 void *
3054 pwmd_calloc (size_t nmemb, size_t size)
3056 return _xcalloc (nmemb, size);
3059 void *
3060 pwmd_realloc (void *ptr, size_t size)
3062 return _xrealloc (ptr, size);
3065 char *
3066 pwmd_strdup (const char *str)
3068 char *t;
3069 size_t len;
3070 register size_t c;
3072 len = strlen (str);
3073 t = _xmalloc ((len + 1) * sizeof (char));
3074 if (!t)
3075 return NULL;
3077 for (c = 0; c < len; c++)
3078 t[c] = str[c];
3080 t[c] = 0;
3081 return t;
3084 char *
3085 pwmd_strdup_printf (const char *fmt, ...)
3087 va_list ap, ap2;
3088 int len;
3089 char *buf;
3091 if (!fmt)
3092 return NULL;
3094 va_start (ap, fmt);
3095 va_copy (ap2, ap);
3096 len = vsnprintf (NULL, 0, fmt, ap);
3097 va_end (ap);
3098 buf = pwmd_malloc (++len);
3099 if (buf)
3100 vsnprintf (buf, len, fmt, ap2);
3102 va_end (ap2);
3103 return buf;
3106 gpg_error_t
3107 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
3108 size_t * len, pwmd_pinentry_t which)
3110 #ifndef WITH_PINENTRY
3111 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
3112 #else
3113 gpg_error_t rc;
3115 command_start (pwm);
3116 if (which == PWMD_PINENTRY_CONFIRM && pwm->disable_pinentry)
3118 rc = get_password (pwm, NULL, NULL, which, 1);
3119 return FINISH (rc);
3122 rc = _pwmd_getpin (pwm, filename, result, len, which);
3123 return FINISH (rc);
3124 #endif
3127 const char *
3128 pwmd_version ()
3130 return LIBPWMD_VERSION_STR LIBPWMD_GIT_HASH;
3133 unsigned int
3134 pwmd_features ()
3136 unsigned int n = 0;
3138 #ifdef WITH_PINENTRY
3139 n |= PWMD_FEATURE_PINENTRY;
3140 #endif
3141 #ifdef WITH_SSH
3142 n |= PWMD_FEATURE_SSH;
3143 #endif
3144 #ifdef WITH_QUALITY
3145 n |= PWMD_FEATURE_QUALITY;
3146 #endif
3147 #ifdef WITH_GNUTLS
3148 n |= PWMD_FEATURE_GNUTLS;
3149 #endif
3150 return n;
3153 gpg_error_t
3154 pwmd_fd (pwm_t * pwm, int *fd)
3156 if (!pwm || !fd)
3157 return FINISH (GPG_ERR_INV_ARG);
3159 if (pwm->fd == ASSUAN_INVALID_FD)
3160 return FINISH (GPG_ERR_INV_STATE);
3162 *fd = HANDLE2SOCKET (pwm->fd);
3163 return 0;
3166 void
3167 pwmd_set_pointer (pwm_t *pwm, void *data)
3169 pwm->user_data = data;
3172 void *
3173 pwmd_get_pointer (pwm_t *pwm)
3175 return pwm->user_data;
3179 pwmd_gnutls_error (pwm_t *pwm, const char **str)
3181 #ifndef WITH_GNUTLS
3182 (void)pwm;
3183 (void)str;
3184 return 0;
3185 #else
3186 if (str && pwm && pwm->tls_error)
3187 *str = gnutls_strerror (pwm->tls_error);
3189 return pwm ? pwm->tls_error : 0;
3190 #endif
3193 gpg_error_t
3194 pwmd_cancel (pwm_t *pwm)
3196 if (!pwm)
3197 return FINISH (GPG_ERR_INV_ARG);
3199 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
3200 if (pwm->fd == ASSUAN_INVALID_FD && !pwm->tcp)
3201 #else
3202 if (pwm->fd == ASSUAN_INVALID_FD)
3203 #endif
3204 return FINISH (GPG_ERR_INV_STATE);
3206 /* Can only cancel the connection for the time being. */
3207 if (pwm->connected)
3208 return FINISH (GPG_ERR_INV_STATE);
3210 pwm->cancel = 1;
3211 return 0;
3214 gpg_error_t
3215 pwmd_test_quality (const char *str, double *result)
3217 #ifndef WITH_QUALITY
3218 (void)str;
3219 (void)result;
3220 return GPG_ERR_NOT_IMPLEMENTED;
3221 #else
3222 if (!result)
3223 return GPG_ERR_INV_ARG;
3225 *result = ZxcvbnMatch (str, NULL, NULL);
3226 return 0;
3227 #endif
3230 static gpg_error_t
3231 do_pwmd_bulk_append (char **str, gpg_error_t *cmdrc, int with_rc,
3232 const char *id, size_t idsize, const char *cmd,
3233 const char *args, size_t argsize, size_t *offset)
3235 char buf[32];
3236 size_t len = 0, n = 0;
3237 char *s, *p;
3238 int sub = 0;
3239 char *rcbuf = NULL;
3241 if (!str || !id || !*id || (id && !idsize) || (idsize && !id)
3242 || !cmd || !*cmd || (args && *args && !argsize)
3243 || (argsize && (!args || !*args)))
3244 return FINISH (GPG_ERR_INV_ARG);
3246 if (*str && (strlen (*str) < 4 || memcmp (*str, "2:id", 4)))
3247 return FINISH (GPG_ERR_BAD_DATA);
3249 n = 4;
3250 snprintf (buf, sizeof (buf), "%zu:", idsize);
3251 n += strlen (buf) + idsize + 4;
3252 snprintf (buf, sizeof (buf), " %zu:", strlen (cmd));
3253 n += strlen (buf) + strlen (cmd);
3254 snprintf (buf, sizeof (buf), "%zu:", argsize);
3255 n += strlen (buf) + argsize;
3257 if (with_rc)
3259 int i;
3260 char *t;
3262 for (i = 0; cmdrc[i] != GPG_ERR_MISSING_ERRNO; i++)
3264 t = pwmd_strdup_printf ("%u|%s", cmdrc[i], rcbuf ? rcbuf : "");
3265 if (!t)
3267 pwmd_free (rcbuf);
3268 return FINISH (GPG_ERR_ENOMEM);
3271 pwmd_free (rcbuf);
3272 rcbuf = t;
3275 if (rcbuf)
3277 rcbuf[strlen (rcbuf)-1] = 0;
3278 t = pwmd_strdup_printf ("2:rc%u:%s", strlen (rcbuf), rcbuf);
3279 pwmd_free (rcbuf);
3280 if (!t)
3281 return FINISH (GPG_ERR_ENOMEM);
3283 rcbuf = t;
3284 n += strlen (rcbuf);
3285 sub = 1;
3289 if (*str)
3290 len = strlen (*str);
3292 if (offset && *offset < len)
3293 sub = 1;
3295 if (sub)
3296 n += 2; // Parentheses for this sub-command
3298 s = pwmd_malloc ((n + 1) * sizeof (char));
3299 if (!s)
3301 pwmd_free (rcbuf);
3302 return FINISH (GPG_ERR_ENOMEM);
3305 len = 0;
3306 if (with_rc && rcbuf)
3308 memcpy (&s[len], rcbuf, strlen (rcbuf));
3309 len += strlen (rcbuf);
3310 pwmd_free (rcbuf);
3313 if (sub)
3314 memcpy (&s[len++], "(", 1);
3316 snprintf (buf, sizeof (buf), "2:id%zu:", idsize);
3317 memcpy (&s[len], buf, strlen (buf));
3318 len += strlen (buf);
3319 memcpy (&s[len], id, idsize);
3320 len += idsize;
3322 snprintf (buf, sizeof (buf), "%zu:", strlen (cmd));
3323 memcpy (&s[len], buf, strlen (buf));
3324 len += strlen (buf);
3325 memcpy (&s[len], cmd, strlen (cmd));
3326 len += strlen (cmd);
3328 snprintf (buf, sizeof (buf), "%zu:", argsize);
3329 memcpy (&s[len], buf, strlen (buf));
3330 len += strlen (buf);
3331 if (args)
3332 memcpy (&s[len], args, argsize);
3333 len += argsize;
3335 if (sub)
3336 memcpy (&s[len++], ")", 1);
3338 s[len] = 0;
3340 n = *str ? strlen (*str) : 0;
3341 p = pwmd_realloc (*str, (n+len+1) * sizeof (char));
3342 if (!p)
3344 pwmd_free (s);
3345 return FINISH (GPG_ERR_ENOMEM);
3348 if (offset)
3350 memmove (&p[*offset+len], &p[*offset], n - *offset);
3351 memcpy (&p[*offset], s, len);
3352 *offset += len;
3354 else
3355 memcpy (&p[n], s, len);
3357 p[n+len] = 0;
3358 *str = p;
3360 pwmd_free (s);
3361 return FINISH (0);
3364 gpg_error_t
3365 pwmd_bulk_append (char **str, const char *id, size_t idsize, const char *cmd,
3366 const char *args, size_t argsize, size_t *offset)
3368 return do_pwmd_bulk_append (str, 0, 0, id, idsize, cmd, args, argsize,
3369 offset);
3372 /* Consider the return code of the previous command and run the the specified
3373 * command when it matches. Creates the following syntax which trails the
3374 * previous commands syntax:
3376 * 2:rc<R>:<rc>[|<rc>[...]](2:id...)
3378 * To consider the return code for the previous command added with this
3379 * function, decrement offset by 1 to place the current command inside the
3380 * parentheses of the previous command.
3382 gpg_error_t
3383 pwmd_bulk_append_rc (char **str, gpg_error_t *rc, const char *id,
3384 size_t idsize, const char *cmd, const char *args,
3385 size_t argsize, size_t *offset)
3387 return do_pwmd_bulk_append (str, rc, 1, id, idsize, cmd, args, argsize,
3388 offset);
3391 gpg_error_t
3392 pwmd_bulk_finalize (char **str)
3394 size_t slen = 0;
3395 char *p;
3397 if (!str)
3398 return FINISH (GPG_ERR_INV_ARG);
3400 if (!*str || strlen (*str) < 4 || memcmp (*str, "2:id", 4))
3401 return FINISH (GPG_ERR_BAD_DATA);
3403 slen = strlen (*str);
3404 p = pwmd_realloc (*str, (slen+2+1) * sizeof (char));
3405 if (!p)
3406 return FINISH (GPG_ERR_ENOMEM);
3408 memmove (&p[1], p, slen);
3409 p[0] = '(';
3410 p[++slen] = ')';
3411 p[++slen] = 0;
3412 *str = p;
3413 return FINISH (0);
3416 gpg_error_t
3417 pwmd_bulk_result (const char *str, size_t size, const char *id, size_t id_size,
3418 size_t *offset, const char **result, size_t *result_len,
3419 gpg_error_t *cmd_rc)
3421 const char *s;
3422 size_t o;
3423 gpg_error_t rrc = 0;
3424 int match = 0;
3426 if (!str || !size || !id || !id_size || !offset)
3427 return FINISH (GPG_ERR_INV_ARG);
3429 s = str + *offset;
3430 o = *offset;
3432 if (result)
3433 *result = NULL;
3435 if (result_len)
3436 *result_len = 0;
3438 if (cmd_rc)
3439 *cmd_rc = 0;
3441 if (strlen (str) < 15 || memcmp (str, "(11:bulk-result", 15))
3442 return FINISH (GPG_ERR_BAD_DATA);
3443 else if (!o)
3445 s += 15;
3446 o += 15;
3449 for (;;)
3451 size_t len;
3452 char *e = NULL;
3453 char buf[32];
3455 if (size - o < 4 || memcmp (s, "2:id", 4))
3456 return FINISH (GPG_ERR_NOT_FOUND);
3458 s += 4;
3459 o += 4;
3461 if (!isdigit (*s))
3462 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC);
3464 len = atoi (s);
3465 while (isdigit (*s))
3466 s++, o++;
3468 if (*s != ':')
3469 return FINISH (GPG_ERR_INV_SEXP);
3471 s++, o++;
3473 if (size - o < len)
3474 return FINISH (GPG_ERR_NOT_FOUND);
3476 /* Continue processing even though this command doesn't match. Commands
3477 * should be processed in the order the were added so this is safe to do.
3478 * If the command is not found then that means a previous command failed.
3479 * We can't do a strstr() or memmem() for the next "2:id" because command
3480 * result data may contain those bytes.
3482 if (id_size == len && !memcmp (s, id, len))
3483 match = 1;
3485 s += len, o += len;
3487 if (!isdigit (*s))
3488 return FINISH (GPG_ERR_SEXP_STRING_TOO_LONG);
3490 if (size - o < 4 || memcmp (s, "2:rc", 4))
3491 return FINISH (GPG_ERR_INV_SEXP);
3493 s += 4, o += 4;
3494 if (!isdigit (*s))
3495 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC);
3497 e = NULL;
3498 len = strtoul (s, &e, 10);
3499 if (e && *e != ':')
3500 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC);
3502 if (len >= sizeof (buf))
3503 return FINISH (GPG_ERR_SEXP_STRING_TOO_LONG);
3505 while (isdigit (*s))
3506 s++, o++;
3508 if (*s != ':')
3509 return FINISH (GPG_ERR_INV_SEXP);
3511 s++, o++;
3512 strncpy (buf, s, len);
3513 buf[len] = 0;
3514 if (len > strlen (buf))
3515 return FINISH (GPG_ERR_SEXP_STRING_TOO_LONG);
3517 e = NULL;
3518 rrc = strtoul (buf, &e, 10);
3519 if (e && *e)
3520 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC);
3522 s += len;
3523 o += len;
3525 // Data length
3526 e = NULL;
3527 len = strtoul (s, &e, 10);
3528 if (e && *e != ':')
3529 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC);
3531 while (isdigit (*s))
3532 s++, o++;
3534 if (*s != ':')
3535 return FINISH (GPG_ERR_INV_SEXP);
3537 s++, o++;
3538 o += len;
3540 // If no match, continue searching for the command id.
3541 if (match)
3543 if (result)
3544 *result = s;
3546 if (result_len)
3547 *result_len = len;
3549 if (cmd_rc)
3550 *cmd_rc = rrc;
3552 *offset = o;
3553 return FINISH (0);
3557 return FINISH (GPG_ERR_NOT_FOUND);