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
29 #include <sys/types.h>
48 # ifdef HAVE_TERMIOS_H
51 # ifdef HAVE_SYS_SOCKET_H
52 # include <sys/socket.h>
55 # include <sys/wait.h>
57 # include <sys/select.h>
64 #include "util-string.h"
83 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
84 #include <sys/types.h>
86 # ifdef HAVE_SYS_SOCKET_H
87 # include <sys/socket.h>
92 # ifdef HAVE_NETINET_IN_H
93 # include <netinet/in.h>
106 #define TEST_BULK_OFFSET(a, b) (a -= b == a ? 0 : 1)
107 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
117 struct bulk_inquire_s
123 pwmd_inquire_cb_t func
;
126 static gpg_error_t
status_cb (void *data
, const char *line
);
129 hook_read (assuan_context_t ctx
, assuan_fd_t fd
, void *data
, size_t len
)
131 pwm_t
*pwm
= assuan_get_pointer (ctx
);
134 return pwm
->read_cb (pwm
->read_cb_data
, HANDLE2SOCKET (fd
), data
, len
);
136 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
138 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->ssh
)
140 ssize_t ret
= read_hook_ssh (pwm
->tcp
->ssh
, fd
, data
, len
);
146 __assuan_close (ctx
, pwm
->fd
);
147 pwm
->fd
= ASSUAN_INVALID_FD
;
155 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->tls
)
156 return tls_read_hook (pwm
, fd
, data
, len
);
160 return read (HANDLE2SOCKET (fd
), data
, len
);
164 hook_write (assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
167 pwm_t
*pwm
= assuan_get_pointer (ctx
);
171 return pwm
->write_cb (pwm
->write_cb_data
, HANDLE2SOCKET (fd
), data
, len
);
173 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
175 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->ssh
)
177 ssize_t ret
= write_hook_ssh (pwm
->tcp
->ssh
, fd
, data
, len
);
183 __assuan_close (ctx
, pwm
->fd
);
184 pwm
->fd
= ASSUAN_INVALID_FD
;
192 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->tls
)
193 return tls_write_hook (pwm
, fd
, data
, len
);
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
);
211 hook_waitpid (assuan_context_t ctx
, pid_t pid
, int action
, int *status
,
216 return waitpid (pid
, status
, options
);
223 static int initialized
;
226 // May be called more than once.
227 gnutls_global_init ();
234 bindtextdomain ("libpwmd", LOCALEDIR
);
240 gpgrt_set_alloc_func (_xrealloc_gpgrt
);
257 gnutls_global_deinit ();
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
);
276 else if (pwm
->bulk_id
)
277 return rc
? rc
: GPG_ERR_ASS_NO_INQUIRE_CB
;
282 *data
= (char *)inq
->data
;
288 _connect_finalize (pwm_t
* pwm
)
291 assuan_fd_t active
[2];
292 int n
= assuan_get_active_fds (pwm
->ctx
, 0, active
, N_ARRAY (active
));
294 size_t offset
= 0, toffset
;
295 gpg_error_t rcs
[] = { 0, GPG_ERR_MISSING_ERRNO
};
298 return GPG_ERR_EBADFD
;
302 pwm
->pinentry_pid
= -1;
305 rc
= pwmd_bulk_append (&bulk
, "VERSION", strlen ("VERSION"), "GETINFO",
306 "VERSION", strlen ("VERSION"), &offset
);
308 if (!rc
&& (pwm
->opts
& OPT_STATE_STATUS
))
310 char *buf
= pwmd_strdup_printf ("client-state=1");
313 rc
= pwmd_bulk_append_rc (&bulk
, rcs
, "STATE", 5, "OPTION", buf
,
314 strlen (buf
), &offset
);
321 if (!rc
&& pwm
->name
)
323 char *buf
= pwmd_strdup_printf ("NAME=%s", pwm
->name
);
325 TEST_BULK_OFFSET (offset
, toffset
);
327 rc
= pwmd_bulk_append_rc (&bulk
, rcs
, "NAME", strlen ("NAME"), "OPTION",
328 buf
, strlen (buf
), &offset
);
336 rc
= pwmd_bulk_finalize (&bulk
);
343 rc
= pwmd_bulk (pwm
, &result
, &size
, NULL
, NULL
, bulk
, strlen (bulk
));
353 rc
= pwmd_bulk_result (result
, size
, "STATE", 5, &offset
, &r
,
355 if (gpg_err_code (rc
) == GPG_ERR_NOT_FOUND
)
361 rc
= pwmd_bulk_result (result
, size
, "VERSION", 7, &offset
, &r
,
364 pwm
->version
= strtoul (r
, NULL
, 16);
367 rc
= pwmd_bulk_result (result
, size
, "NAME", 4, &offset
, &r
,
370 if (gpg_err_code (rc
) == GPG_ERR_NOT_FOUND
)
385 connect_uds (pwm_t
* pwm
, const char *path
)
388 return GPG_ERR_UNSUPPORTED_PROTOCOL
;
391 return GPG_ERR_INV_ARG
;
393 char *socketpath
= NULL
;
398 pwbuf
= _getpwuid (&pw
);
400 return gpg_error_from_syserror ();
403 socketpath
= pwmd_strdup_printf ("%s/.pwmd/socket", pw
.pw_dir
);
405 socketpath
= _expand_homedir ((char *) path
, &pw
);
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
);
418 init_handle (pwm_t
* pwm
)
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
,
433 NULL
, //sendmsg both are used for FD passing
445 rc
= assuan_new_ext (&pwm
->ctx
, GPG_ERR_SOURCE_DEFAULT
, &mhooks
, NULL
,
450 assuan_set_pointer (pwm
->ctx
, pwm
);
451 assuan_ctx_set_system_hooks (pwm
->ctx
, &shooks
);
455 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
457 free_tcp (pwm_t
*pwm
)
459 struct tcp_s
*tcp
= pwm
->tcp
;
465 _free_ssh_conn (tcp
->ssh
);
471 pwmd_free (tcp
->host
);
474 freeaddrinfo (tcp
->addrs
);
478 pthread_cond_destroy (&tcp
->dns_cond
);
479 pthread_mutex_destroy (&tcp
->dns_mutex
);
485 lookup_host (pwm_t
*pwm
)
487 struct addrinfo hints
= { 0 };
494 hints
.ai_family
= AF_UNSPEC
;
497 hints
.ai_family
= AF_INET
;
500 hints
.ai_family
= AF_INET6
;
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
);
514 return gpg_error_from_syserror ();
517 return GPG_ERR_EAGAIN
;
519 return GPG_ERR_ENOMEM
;
521 return GPG_ERR_UNKNOWN_HOST
;
526 return GPG_ERR_DNS_UNKNOWN
;
531 resolve_host_thread (void *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
;
547 tcp_connect_common (pwm_t
* pwm
)
552 #define TS_TIMEOUT 50000000L
556 pwm
->tcp
->flags
&= ~TCP_FLAG_DNS_FINISHED
;
558 n
= pthread_create (&tid
, NULL
, resolve_host_thread
, pwm
);
560 return gpg_error_from_errno (n
);
562 pthread_mutex_lock (&pwm
->tcp
->dns_mutex
);
567 gpg_error_t
*result
= NULL
;
569 clock_gettime (CLOCK_REALTIME
, &ts
);
570 if (ts
.tv_nsec
+ TS_TIMEOUT
>= 1000000000LL) {
575 ts
.tv_nsec
+= TS_TIMEOUT
;
579 #ifdef HAVE_PTHREAD_CANCEL
580 pthread_cancel (tid
);
581 pthread_join (tid
, NULL
);
583 pthread_join (tid
, (void **)&result
);
586 return GPG_ERR_CANCELED
;
589 n
= pthread_cond_timedwait (&pwm
->tcp
->dns_cond
, &pwm
->tcp
->dns_mutex
,
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
);
599 pthread_join (tid
, (void **)&result
);
602 return GPG_ERR_ETIMEDOUT
;
607 else if (n
&& n
!= ETIMEDOUT
)
609 #ifdef HAVE_PTHREAD_CANCEL
610 pthread_cancel (tid
);
611 pthread_join (tid
, NULL
);
613 pthread_join (tid
, (void **)&result
);
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
);
631 rc
= lookup_host (pwm
);
637 for (pwm
->tcp
->addr
= pwm
->tcp
->addrs
; pwm
->tcp
->addr
;
638 pwm
->tcp
->addr
= pwm
->tcp
->addrs
->ai_next
)
641 pwm
->fh
= _open_osfhandle (socket (pwm
->tcp
->addr
->ai_family
, SOCK_STREAM
, 0), 0);
642 pwm
->fd
= SOCKET2HANDLE (_get_osfhandle (pwm
->fh
));
644 pwm
->fd
= socket (pwm
->tcp
->addr
->ai_family
, SOCK_STREAM
, 0);
646 if (pwm
->fd
== ASSUAN_INVALID_FD
)
648 rc
= gpg_error_from_syserror ();
649 if (pwm
->tcp
->addr
== pwm
->tcp
->addrs
->ai_next
)
654 rc
= set_non_blocking (pwm
->fd
, 1);
657 __assuan_close (pwm
->ctx
, pwm
->fd
);
658 pwm
->fd
= ASSUAN_INVALID_FD
;
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)
669 unsigned elapsed
= 0;
671 rc
= gpg_error_from_syserror ();
673 int w
= WSAGetLastError ();
678 rc
= GPG_ERR_EINPROGRESS
;
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
)
698 FD_SET (HANDLE2SOCKET (pwm
->fd
), &wfds
);
699 n
= select (HANDLE2SOCKET (pwm
->fd
)+1, NULL
, &wfds
, NULL
, &tv
);
701 if (!n
|| pwm
->cancel
)
704 rc
= gpg_error (GPG_ERR_CANCELED
);
705 else if (++elapsed
>= pwm
->socket_timeout
)
706 rc
= gpg_error (GPG_ERR_ETIMEDOUT
);
712 socklen_t len
= sizeof (int);
717 getsockopt (HANDLE2SOCKET (pwm
->fd
), SOL_SOCKET
, SO_ERROR
, &ret
, &len
);
719 rc
= gpg_error_from_errno (ret
);
721 getsockopt (pwm
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
723 rc
= gpg_error_from_errno (n
);
727 rc
= gpg_error_from_syserror ();
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
747 rc
= set_non_blocking (pwm
->fd
, 0);
750 __assuan_close (pwm
->ctx
, pwm
->fd
);
751 pwm
->fd
= ASSUAN_INVALID_FD
;
760 command_start (pwm_t
*pwm
)
762 pwm
->pin_repeated
= 0;
767 pwmd_connect_fd (pwm_t
* pwm
, int fd
)
772 return FINISH (GPG_ERR_INV_ARG
);
775 rc
= init_handle (pwm
);
779 else if (pwm
->fd
!= ASSUAN_INVALID_FD
)
780 return FINISH (GPG_ERR_INV_STATE
);
785 if (!(pwm
->opts
& OPT_SIGPIPE
))
787 struct sigaction sa
= { 0 };
789 sa
.sa_handler
= SIG_IGN
;
790 sigaction (SIGPIPE
, &sa
, NULL
);
794 rc
= assuan_socket_connect_fd (pwm
->ctx
, fd
, 0);
797 pwm
->fd
= SOCKET2HANDLE (fd
);
798 pwm
->connected
= pwm
->user_fd
= 1;
799 rc
= _connect_finalize (pwm
);
803 pwmd_disconnect (pwm
);
809 pwmd_connect (pwm_t
* pwm
, const char *url
, ...)
815 return FINISH (GPG_ERR_INV_ARG
);
818 rc
= init_handle (pwm
);
820 return FINISH (GPG_ERR_INV_ARG
);
822 else if (pwm
->fd
!= ASSUAN_INVALID_FD
)
823 return FINISH (GPG_ERR_INV_STATE
);
828 if (!(pwm
->opts
& OPT_SIGPIPE
))
830 struct sigaction sa
= { 0 };
832 sa
.sa_handler
= SIG_IGN
;
833 sigaction (SIGPIPE
, &sa
, NULL
);
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))
848 #ifdef DEFAULT_PWMD_SOCKET
850 p
= DEFAULT_PWMD_SOCKET
;
852 rc
= connect_uds (pwm
, p
);
854 else if (!strncmp (p
, "ssh://", 6) || !strncmp (p
, "ssh6://", 7) ||
855 !strncmp (p
, "ssh4://", 7))
858 return FINISH (GPG_ERR_NOT_IMPLEMENTED
);
862 char *username
= NULL
;
864 if (!strncmp (p
, "ssh6://", 7))
866 pwm
->prot
= PWMD_IPV6
;
869 else if (!strncmp (p
, "ssh4://", 7))
871 pwm
->prot
= PWMD_IPV4
;
876 pwm
->prot
= PWMD_IP_ANY
;
880 rc
= _parse_ssh_url (p
, &host
, &port
, &username
);
884 char *identity
= NULL
;
885 char *knownhosts
= NULL
;
888 identity
= va_arg (ap
, char *);
890 if (!identity
&& pwm
->use_agent
!= 1)
891 rc
= GPG_ERR_INV_ARG
;
893 knownhosts
= va_arg (ap
, char *);
898 rc
= _do_ssh_connect (pwm
, host
, port
, identity
, username
,
902 rc
= _connect_finalize (pwm
);
909 pwmd_free (username
);
910 pwm
->local_pinentry
= 1;
911 pwmd_free (pwm
->ssh_passphrase
);
912 pwm
->ssh_passphrase
= NULL
;
915 else if (!strncmp (p
, "tls://", 6) || !strncmp (p
, "tls6://", 7) ||
916 !strncmp (p
, "tls4://", 7))
919 return FINISH (GPG_ERR_NOT_IMPLEMENTED
);
924 if (!strncmp (p
, "tls6://", 7))
926 pwm
->prot
= PWMD_IPV6
;
929 else if (!strncmp (p
, "tls4://", 7))
931 pwm
->prot
= PWMD_IPV4
;
936 pwm
->prot
= PWMD_IP_ANY
;
940 rc
= tls_parse_url (p
, &host
, &port
);
944 char *clientcert
= NULL
;
945 char *clientkey
= NULL
;
947 char *server_fp
= NULL
;
950 clientcert
= va_arg (ap
, char *);
953 rc
= GPG_ERR_INV_ARG
;
956 clientkey
= va_arg (ap
, char *);
958 rc
= GPG_ERR_INV_ARG
;
961 cacert
= va_arg (ap
, char *);
963 rc
= GPG_ERR_INV_ARG
;
965 server_fp
= va_arg (ap
, char *);
972 rc
= tls_connect (pwm
, host
, port
, clientcert
, clientkey
, cacert
,
973 pwm
->tls_priority
, server_fp
, pwm
->tls_verify
);
976 rc
= _connect_finalize (pwm
);
983 pwm
->local_pinentry
= 1;
994 disconnect (pwm_t
* pwm
)
1000 assuan_release (pwm
->ctx
);
1002 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1006 pwm
->fd
= ASSUAN_INVALID_FD
;
1012 pwmd_close (pwm_t
* 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
1035 _pinentry_disconnect (pwm
);
1042 inquire_realloc_cb (void *data
, const void *buffer
, size_t len
)
1044 membuf_t
*mem
= (membuf_t
*) data
;
1051 if ((p
= pwmd_realloc (mem
->buf
, mem
->len
+ len
)) == NULL
)
1052 return gpg_error (GPG_ERR_ENOMEM
);
1055 memcpy ((char *) mem
->buf
+ mem
->len
, buffer
, 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
);
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
;
1076 struct termios told
, tnew
;
1086 if (!isatty (STDIN_FILENO
))
1088 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
1089 return GPG_ERR_ENOTTY
;
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)
1106 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
1107 return gpg_error_from_errno (n
);
1112 if (pwm
->passphrase_hint
)
1113 fprintf(stderr
, N_("Key info: %s\n"), pwm
->passphrase_hint
);
1117 case PWMD_PINENTRY_OPEN
:
1118 fprintf (stderr
, N_("Passphrase for %s: "), pwm
->filename
);
1120 case PWMD_PINENTRY_OPEN_FAILED
:
1121 fprintf (stderr
, N_("Invalid passphrase. Passphrase for %s: "),
1124 case PWMD_PINENTRY_SAVE
:
1125 fprintf (stderr
, N_("New passphrase for %s: "), pwm
->filename
);
1127 case PWMD_PINENTRY_SAVE_CONFIRM
:
1128 fprintf (stderr
, N_("Repeat passphrase: "));
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
);
1137 fprintf(stderr
, N_("Confirm [y/N]:"));
1142 p
= fgets (buf
, sizeof (buf
), stdin
);
1146 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
1149 if (!p
|| feof (stdin
))
1152 return GPG_ERR_CANCELED
;
1155 /* Strip the newline character. */
1156 p
[strlen (p
) - 1] = 0;
1160 if (w
== PWMD_PINENTRY_CONFIRM
)
1162 if (*p
!= 'y' && *p
!= 'Y')
1163 return GPG_ERR_CANCELED
;
1167 key
= pwmd_strdup_printf ("%s", p
);
1168 wipememory (buf
, 0, sizeof (buf
));
1170 return GPG_ERR_ENOMEM
;
1176 *len
= strlen (key
);
1180 if (w
== PWMD_PINENTRY_CONFIRM
)
1181 return GPG_ERR_CANCELED
;
1183 /* To satisfy inquire_cb(). */
1185 *result
= pwmd_strdup ("");
1195 pwmd_password (pwm_t
* pwm
, const char *keyword
, char **data
, size_t * size
)
1198 int new_password
= 0;
1199 char *password
= NULL
, *newpass
= NULL
;
1202 command_start (pwm
);
1210 if (!strcmp (keyword
, "NEW_PASSPHRASE"))
1213 if (!new_password
&& pwm
->pinentry_try
)
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
,
1229 pwmd_pinentry_t which
;
1232 which
= new_password
1233 ? PWMD_PINENTRY_SAVE_FAILED
: PWMD_PINENTRY_OPEN_FAILED
;
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
;
1260 (void) pwmd_getpin (pwm
, pwm
->filename
, NULL
, NULL
, PWMD_PINENTRY_CLOSE
);
1261 pwmd_free (newpass
);
1265 pwmd_free (password
);
1271 inquire_cb (void *data
, const char *keyword
)
1273 pwm_t
*pwm
= (pwm_t
*) data
;
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"))
1282 else if (!strcmp (keyword
, "NEW_PASSPHRASE") || !strcmp (keyword
, "GENKEY"))
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
);
1297 if (!pwm
->override_inquire
&& (is_password
|| new_password
))
1300 rc
= pwmd_password (data
, keyword
, &result
, &len
);
1305 rc
= pwm
->inquire_func (pwm
->inquire_data
, keyword
, rc
, &result
,
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
;
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);
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.
1354 if (gpg_err_code (rc
) == GPG_ERR_EOF
|| !rc
)
1356 if (len
<= 0 && !result
)
1361 else if ((len
<= 0 && result
) || (len
&& !result
))
1363 rc
= gpg_error (GPG_ERR_INV_ARG
);
1367 if (pwm
->inquire_maxlen
1368 && pwm
->inquire_sent
+ len
> pwm
->inquire_maxlen
)
1370 rc
= gpg_error (GPG_ERR_TOO_LARGE
);
1372 rc
= pwm
->inquire_func (pwm
->inquire_data
, keyword
, rc
,
1377 arc
= assuan_send_data (pwm
->ctx
, result
, len
);
1378 if (gpg_err_code (rc
) == GPG_ERR_EOF
)
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
);
1409 pwm
->inquire_maxlen
= pwm
->inquire_sent
= 0;
1414 parse_assuan_line (pwm_t
* pwm
)
1420 rc
= assuan_read_line (pwm
->ctx
, &line
, &len
);
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] == ' '))
1438 rc
= strtol (line
, NULL
, 10);
1446 reset_handle (pwm_t
*pwm
)
1448 pwm
->fd
= ASSUAN_INVALID_FD
;
1451 pwm
->pinentry_disabled
= 0;
1452 pwm
->lock_timeout
= -2;
1453 #ifdef WITH_PINENTRY
1455 _pinentry_disconnect (pwm
);
1457 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1470 pwmd_disconnect (pwm_t
* 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
);
1485 /* Note that this should only be called when not in a command. */
1487 pwmd_process (pwm_t
* pwm
)
1491 struct timeval tv
= { 0, 0 };
1494 if (!pwm
|| pwm
->fd
== ASSUAN_INVALID_FD
)
1495 return FINISH (GPG_ERR_INV_ARG
);
1497 return FINISH (GPG_ERR_INV_STATE
);
1501 FD_SET (_get_osfhandle (pwm
->fh
), &fds
);
1503 FD_SET (pwm
->fd
, &fds
);
1505 n
= select (HANDLE2SOCKET (pwm
->fd
) + 1, &fds
, NULL
, NULL
, &tv
);
1510 switch (WSAGetLastError ())
1513 gpg_err_set_errno (EBADF
);
1515 case WSAEWOULDBLOCK
:
1516 gpg_err_set_errno (EAGAIN
);
1519 case ERROR_BROKEN_PIPE
:
1520 gpg_err_set_errno (EPIPE
);
1523 gpg_err_set_errno (EIO
);
1527 return FINISH (gpg_error_from_syserror ());
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
;
1551 status_cb (void *data
, const char *line
)
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);
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
1587 char *p
= strchr (line
, ' ');
1588 size_t a
= strtoul (++p
, NULL
, 10);
1590 char buf
[ASSUAN_LINELENGTH
];
1594 while (isdigit (*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
);
1603 else if (!strcmp (line
, "REHANDSHAKE"))
1608 ret
= tls_read_hook (pwm
, pwm
->fd
, buf
, sizeof (buf
));
1611 pwm
->tls_error
= ret
;
1612 return GPG_ERR_GENERAL
;
1617 if (pwm
->status_func
)
1618 return pwm
->status_func (pwm
->status_data
, line
);
1624 _assuan_command (pwm_t
* pwm
, assuan_context_t ctx
,
1625 char **result
, size_t * len
, const char *cmd
)
1631 return FINISH (GPG_ERR_INV_ARG
);
1633 if (strlen (cmd
) >= ASSUAN_LINELENGTH
+ 1)
1634 return FINISH (GPG_ERR_LINE_TOO_LONG
);
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
,
1653 pwmd_free (data
.buf
);
1661 inquire_realloc_cb (&data
, "", 1);
1664 *result
= (char *) data
.buf
;
1666 pwmd_free (data
.buf
);
1673 pwm
->inquire_maxlen
= 0;
1678 pwmd_command_ap (pwm_t
* pwm
, char **result
, size_t * rlen
,
1679 pwmd_inquire_cb_t func
, void *user
, const char *cmd
,
1687 return GPG_ERR_INV_ARG
;
1689 command_start (pwm
);
1698 return FINISH (GPG_ERR_INV_ARG
);
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.
1707 len
= vsnprintf (NULL
, 0, cmd
, ap
);
1708 buf
= (char *) pwmd_malloc (len
+1);
1712 return FINISH (GPG_ERR_ENOMEM
);
1715 if (vsnprintf (buf
, len
+1, cmd
, ap2
) != len
)
1719 return FINISH (GPG_ERR_ENOMEM
);
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
);
1737 pwmd_command (pwm_t
* pwm
, char **result
, size_t * len
,
1738 pwmd_inquire_cb_t func
, void *user
, const char *cmd
, ...)
1749 return FINISH (GPG_ERR_INV_ARG
);
1751 return FINISH (GPG_ERR_INV_STATE
);
1754 gpg_error_t rc
= pwmd_command_ap (pwm
, result
, len
, func
, user
, cmd
, ap
);
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
)
1764 struct bulk_inquire_s
*inq
;
1767 return GPG_ERR_INV_ARG
;
1770 return FINISH (GPG_ERR_INV_STATE
);
1778 inq
= pwmd_calloc (1, sizeof (struct bulk_inquire_s
));
1780 return FINISH (GPG_ERR_ENOMEM
);
1782 command_start (pwm
);
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
;
1799 set_pinentry_options (pwm_t
* pwm
, int which
, char **cmds
, size_t *offset
)
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
);
1813 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_TTY", strlen ("PIN_TTY"),
1814 "OPTION", str
, strlen (str
), offset
);
1816 rc
= GPG_ERR_ENOMEM
;
1821 if (!rc
&& pwm
->pinentry_term
)
1823 str
= pwmd_strdup_printf ("TTYTYPE=%s", pwm
->pinentry_term
);
1826 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_TERM", strlen ("PIN_TERM"),
1827 "OPTION", str
, strlen (str
), offset
);
1829 rc
= GPG_ERR_ENOMEM
;
1834 if (!rc
&& pwm
->pinentry_display
)
1836 str
= pwmd_strdup_printf ("DISPLAY=%s", pwm
->pinentry_display
);
1839 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_DISPLAY",
1840 strlen ("PIN_DISPLAY"), "OPTION", str
,
1841 strlen (str
), offset
);
1843 rc
= GPG_ERR_ENOMEM
;
1848 if (!rc
&& pwm
->pinentry_desc
)
1850 str
= pwmd_strdup_printf ("DESC=%s", pwm
->pinentry_desc
);
1853 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_DESC", strlen ("PIN_DESC"),
1854 "OPTION", str
, strlen (str
), offset
);
1856 rc
= GPG_ERR_ENOMEM
;
1861 if (!rc
&& pwm
->pinentry_lcctype
)
1863 str
= pwmd_strdup_printf ("LC_CTYPE=%s", pwm
->pinentry_lcctype
);
1866 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_LCCTYPE",
1867 strlen ("PIN_LCCTYPE"), "OPTION", str
,
1868 strlen (str
), offset
);
1870 rc
= GPG_ERR_ENOMEM
;
1875 if (!rc
&& pwm
->pinentry_lcmessages
)
1877 str
= pwmd_strdup_printf ("LC_MESSAGES=%s", pwm
->pinentry_lcmessages
);
1880 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_LCMESSAGES",
1881 strlen ("PIN_LCMESSAGES"), "OPTION", str
,
1882 strlen (str
), offset
);
1884 rc
= GPG_ERR_ENOMEM
;
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
);
1897 rc
= pwmd_bulk_append_rc (cmds
, rcs
, "PIN_TIMEOUT",
1898 strlen ("PIN_TIMEOUT"), "OPTION", str
,
1899 strlen (str
), offset
);
1901 rc
= GPG_ERR_ENOMEM
;
1905 pwm
->current_pinentry_timeout
= pwm
->pinentry_timeout
;
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
;
1928 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1930 if (pwm
->tcp
&& pwm
->tcp
->ssh
)
1931 *result
= PWMD_SOCKET_SSH
;
1934 if (pwm
->tcp
&& pwm
->tcp
->tls
)
1935 *result
= PWMD_SOCKET_TLS
;
1942 disable_pinentry (pwm_t
*pwm
, int *disable
, char **cmds
, size_t *offset
,
1946 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1947 int no_pinentry
= pwm
->disable_pinentry
|| pwm
->tcp
|| pwm
->local_pinentry
;
1949 int no_pinentry
= pwm
->disable_pinentry
|| pwm
->local_pinentry
;
1952 gpg_error_t rcs
[] = { 0, GPG_ERR_MISSING_ERRNO
};
1955 no_pinentry
= !!force
;
1958 *disable
= no_pinentry
;
1960 if (force
== -1 && pwm
->pinentry_disabled
&& no_pinentry
)
1962 else if (force
== -1 && !pwm
->pinentry_disabled
&& !no_pinentry
)
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
);
1970 rc
= pwmd_bulk_append (cmds
, "PIN_ENABLE", strlen ("PIN_ENABLE"),
1971 "OPTION", buf
, strlen (buf
), NULL
);
1973 rc
= GPG_ERR_ENOMEM
;
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;
1987 rc
= pwmd_bulk_result (result
, size
, "PIN_ENABLE", 10, offset
, &r
, &rsize
,
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
,
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
,
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
,
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
,
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
,
2012 if (!rrc
&& (!rc
|| gpg_err_code (rc
) == GPG_ERR_NOT_FOUND
))
2013 rc
= pwmd_bulk_result (result
, size
, "PIN_LCMESSAGES", 14, offset
, &r
,
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
,
2020 if (gpg_err_code (rc
) == GPG_ERR_NOT_FOUND
)
2023 return rc
? rc
: rrc
;
2027 pwmd_open (pwm_t
* pwm
, const char *filename
, pwmd_inquire_cb_t cb
,
2031 int no_pinentry
= 0;
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
);
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
);
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
);
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
);
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
);
2075 rc
= GPG_ERR_ENOMEM
;
2081 buf
= pwmd_strdup_printf ("%s%s", (pwm
->opts
& OPT_LOCK_ON_OPEN
)
2082 ? "--lock " : "", filename
);
2085 TEST_BULK_OFFSET (offset
, toffset
);
2086 rc
= pwmd_bulk_append_rc (&cmds
, rcs
, "OPEN", strlen ("OPEN"),
2087 "OPEN", buf
, strlen (buf
), &offset
);
2090 rc
= GPG_ERR_ENOMEM
;
2095 rc
= disable_pinentry (pwm
, &no_pinentry
, &cmds
, &offset
, 0);
2097 rc
= pwmd_bulk_finalize (&cmds
);
2105 rc
= pwmd_bulk (pwm
, &result
, &size
, cb
, data
, cmds
, strlen (cmds
));
2111 gpg_error_t rrc
= 0;
2115 rc
= parse_pinentry_results (pwm
, result
, size
, &offset
,
2118 if (!rc
|| gpg_err_code (rc
) == GPG_ERR_NOT_FOUND
)
2119 rc
= pwmd_bulk_result (result
, size
, "LOCK_TO", 7, &offset
, &r
,
2122 if (gpg_err_code (rc
) == GPG_ERR_NOT_FOUND
)
2129 rc
= pwmd_bulk_result (result
, size
, "OPEN", 4, &offset
, &r
,
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;
2153 pwmd_free (pwm
->filename
);
2154 pwm
->filename
= NULL
;
2159 pwmd_free (pwm
->passphrase_hint
);
2160 pwmd_free (pwm
->passphrase_info
);
2161 pwm
->passphrase_info
= pwm
->passphrase_hint
= NULL
;
2166 do_pwmd_save_passwd (pwm_t
* pwm
, const char *args
, pwmd_inquire_cb_t cb
,
2167 void *data
, int which
)
2170 int no_pinentry
= 0;
2172 size_t offset
= 0, toffset
;
2173 gpg_error_t rcs
[] = { 0, GPG_ERR_MISSING_ERRNO
};
2176 return FINISH (GPG_ERR_INV_ARG
);
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
);
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
);
2199 buf
= pwmd_strdup_printf ("%s", args
? args
: "");
2201 if (which
== PWMD_WHICH_SAVE
)
2203 else if (which
== PWMD_WHICH_PASSWD
)
2208 TEST_BULK_OFFSET (offset
, toffset
);
2210 rc
= pwmd_bulk_append_rc (&cmds
, rcs
, p
, strlen (p
), p
, buf
,
2211 strlen (buf
), &offset
);
2213 rc
= GPG_ERR_ENOMEM
;
2216 rc
= disable_pinentry (pwm
, &no_pinentry
, &cmds
, &offset
, 0);
2219 rc
= pwmd_bulk_finalize (&cmds
);
2228 rc
= pwmd_bulk (pwm
, &result
, &size
, cb
, data
, cmds
, strlen (cmds
));
2234 gpg_error_t rrc
= 0;
2238 rc
= parse_pinentry_results (pwm
, result
, size
, &offset
,
2242 rc
= pwmd_bulk_result (result
, size
, p
, strlen (p
), &offset
,
2252 pwm
->disable_pinentry
= 0;
2254 pwmd_free (pwm
->passphrase_hint
);
2255 pwmd_free (pwm
->passphrase_info
);
2256 pwm
->passphrase_info
= pwm
->passphrase_hint
= NULL
;
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
);
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
);
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
);
2279 pwmd_get_set_opt (pwm_t
*pwm
, pwmd_option_t opt
, int get
, va_list ap
)
2284 char *arg1
, **charpp
;
2288 return GPG_ERR_INV_ARG
;
2290 command_start (pwm
);
2293 case PWMD_OPTION_SERVER_VERSION
:
2295 return GPG_ERR_NOT_SUPPORTED
;
2298 rc
= GPG_ERR_INV_STATE
;
2301 unsigned *u
= va_arg (ap
, unsigned *);
2306 case PWMD_OPTION_SIGPIPE
:
2309 intp
= va_arg (ap
, int *);
2310 *intp
= pwm
->opts
& OPT_SIGPIPE
? 1 : 0;
2314 n
= va_arg (ap
, int);
2317 rc
= GPG_ERR_INV_VALUE
;
2322 pwm
->opts
|= OPT_SIGPIPE
;
2324 pwm
->opts
&= ~OPT_SIGPIPE
;
2327 case PWMD_OPTION_STATE_STATUS
:
2330 intp
= va_arg (ap
, int *);
2331 *intp
= pwm
->opts
& OPT_STATE_STATUS
? 1 : 0;
2335 n
= va_arg (ap
, int);
2338 rc
= GPG_ERR_INV_VALUE
;
2343 pwm
->opts
|= OPT_STATE_STATUS
;
2345 pwm
->opts
&= ~OPT_STATE_STATUS
;
2348 case PWMD_OPTION_LOCK_ON_OPEN
:
2351 intp
= va_arg (ap
, int *);
2352 *intp
= pwm
->opts
& OPT_LOCK_ON_OPEN
? 1 : 0;
2356 n
= va_arg (ap
, int);
2359 rc
= GPG_ERR_INV_VALUE
;
2364 pwm
->opts
|= OPT_LOCK_ON_OPEN
;
2366 pwm
->opts
&= ~OPT_LOCK_ON_OPEN
;
2369 case PWMD_OPTION_LOCK_TIMEOUT
:
2372 longp
= va_arg (ap
, long *);
2373 *longp
= pwm
->lock_timeout
;
2377 l
= va_arg (ap
, long);
2380 rc
= GPG_ERR_INV_VALUE
;
2384 pwm
->lock_timeout
= l
;
2386 case PWMD_OPTION_INQUIRE_TOTAL
:
2389 sizetp
= va_arg (ap
, size_t *);
2390 *sizetp
= pwm
->inquire_total
;
2394 pwm
->inquire_total
= va_arg (ap
, size_t);
2396 case PWMD_OPTION_STATUS_CB
:
2399 pwmd_status_cb_t
*cb
= va_arg (ap
, pwmd_status_cb_t
*);
2401 *cb
= pwm
->status_func
;
2405 pwm
->status_func
= va_arg (ap
, pwmd_status_cb_t
);
2407 case PWMD_OPTION_STATUS_DATA
:
2410 void **data
= va_arg (ap
, void **);
2412 *data
= pwm
->status_data
;
2416 pwm
->status_data
= va_arg (ap
, void *);
2418 case PWMD_OPTION_NO_PINENTRY
:
2421 intp
= va_arg (ap
, int *);
2422 *intp
= pwm
->disable_pinentry
;
2426 n
= va_arg (ap
, int);
2428 rc
= GPG_ERR_INV_VALUE
;
2430 pwm
->disable_pinentry
= n
;
2432 case PWMD_OPTION_LOCAL_PINENTRY
:
2435 intp
= va_arg (ap
, int *);
2436 *intp
= pwm
->local_pinentry
;
2440 n
= va_arg (ap
, int);
2442 rc
= GPG_ERR_INV_VALUE
;
2444 pwm
->local_pinentry
= n
;
2447 case PWMD_OPTION_PINENTRY_TIMEOUT
:
2450 intp
= va_arg (ap
, int *);
2451 *intp
= pwm
->pinentry_timeout
;
2455 n
= va_arg (ap
, int);
2457 rc
= GPG_ERR_INV_VALUE
;
2459 pwm
->pinentry_timeout
= n
;
2461 case PWMD_OPTION_PINENTRY_TRIES
:
2464 intp
= va_arg (ap
, int *);
2465 *intp
= pwm
->pinentry_tries
;
2469 n
= va_arg (ap
, int);
2471 rc
= GPG_ERR_INV_VALUE
;
2473 pwm
->pinentry_tries
= n
;
2475 case PWMD_OPTION_PINENTRY_PATH
:
2478 charpp
= va_arg (ap
, char **);
2479 *charpp
= (char *)PINENTRY_PATH
;
2483 case PWMD_OPTION_PINENTRY_TTY
:
2486 charpp
= va_arg (ap
, char **);
2487 *charpp
= pwm
->pinentry_tty
;
2491 arg1
= va_arg (ap
, char *);
2492 pwmd_free (pwm
->pinentry_tty
);
2493 pwm
->pinentry_tty
= arg1
? pwmd_strdup (arg1
) : NULL
;
2495 case PWMD_OPTION_PINENTRY_DISPLAY
:
2498 charpp
= va_arg (ap
, char **);
2499 *charpp
= pwm
->pinentry_display
;
2503 arg1
= va_arg (ap
, char *);
2504 pwmd_free (pwm
->pinentry_display
);
2505 pwm
->pinentry_display
= arg1
&& *arg1
? pwmd_strdup (arg1
) : NULL
;
2507 if (!pwm
->pinentry_display
)
2508 unsetenv ("DISPLAY");
2511 case PWMD_OPTION_PINENTRY_TERM
:
2514 charpp
= va_arg (ap
, char **);
2515 *charpp
= pwm
->pinentry_term
;
2519 arg1
= va_arg (ap
, char *);
2520 pwmd_free (pwm
->pinentry_term
);
2521 pwm
->pinentry_term
= arg1
&& *arg1
? pwmd_strdup (arg1
) : NULL
;
2523 if (pwm
->pinentry_term
)
2527 case PWMD_OPTION_PINENTRY_ERROR
:
2530 charpp
= va_arg (ap
, char **);
2531 *charpp
= pwm
->pinentry_error
;
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
;
2540 pwm
->pinentry_error
= arg1
? _percent_escape (arg1
) : NULL
;
2542 case PWMD_OPTION_PINENTRY_PROMPT
:
2545 charpp
= va_arg (ap
, char **);
2546 *charpp
= pwm
->pinentry_prompt
;
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
;
2555 pwm
->pinentry_prompt
= arg1
? _percent_escape (arg1
) : NULL
;
2557 case PWMD_OPTION_PINENTRY_DESC
:
2560 charpp
= va_arg (ap
, char **);
2561 *charpp
= pwm
->pinentry_desc
;
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
;
2570 pwm
->pinentry_desc
= arg1
? _percent_escape (arg1
) : NULL
;
2572 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
2575 charpp
= va_arg (ap
, char **);
2576 *charpp
= pwm
->pinentry_lcctype
;
2580 arg1
= va_arg (ap
, char *);
2581 pwmd_free (pwm
->pinentry_lcctype
);
2582 pwm
->pinentry_lcctype
= arg1
? pwmd_strdup (arg1
) : NULL
;
2584 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
2587 charpp
= va_arg (ap
, char **);
2588 *charpp
= pwm
->pinentry_lcmessages
;
2592 arg1
= va_arg (ap
, char *);
2593 pwmd_free (pwm
->pinentry_lcmessages
);
2594 pwm
->pinentry_lcmessages
= arg1
? pwmd_strdup (arg1
) : NULL
;
2596 case PWMD_OPTION_KNOWNHOST_CB
:
2599 pwmd_knownhost_cb_t
*cb
= va_arg (ap
, pwmd_knownhost_cb_t
*);
2605 pwm
->kh_cb
= va_arg (ap
, pwmd_knownhost_cb_t
);
2607 case PWMD_OPTION_KNOWNHOST_DATA
:
2610 void **data
= va_arg (ap
, void **);
2612 *data
= pwm
->kh_data
;
2616 pwm
->kh_data
= va_arg (ap
, void *);
2618 case PWMD_OPTION_PASSPHRASE_CB
:
2621 pwmd_passphrase_cb_t
*cb
= va_arg (ap
, pwmd_passphrase_cb_t
*);
2623 *cb
= pwm
->passphrase_cb
;
2627 pwm
->passphrase_cb
= va_arg (ap
, pwmd_passphrase_cb_t
);
2629 case PWMD_OPTION_PASSPHRASE_DATA
:
2632 void **data
= va_arg (ap
, void **);
2634 *data
= pwm
->passphrase_data
;
2638 pwm
->passphrase_data
= va_arg (ap
, void *);
2640 case PWMD_OPTION_SSH_AGENT
:
2643 intp
= va_arg (ap
, int *);
2644 *intp
= pwm
->use_agent
;
2648 n
= va_arg (ap
, int);
2650 rc
= GPG_ERR_INV_VALUE
;
2654 case PWMD_OPTION_SSH_PASSPHRASE
:
2656 return GPG_ERR_NOT_SUPPORTED
;
2658 pwmd_free (pwm
->ssh_passphrase
);
2659 pwm
->ssh_passphrase
= NULL
;
2660 arg1
= va_arg (ap
, char *);
2663 pwm
->ssh_passphrase
= pwmd_strdup (arg1
);
2664 if (!pwm
->ssh_passphrase
)
2665 return GPG_ERR_ENOMEM
;
2668 case PWMD_OPTION_SSH_NEEDS_PASSPHRASE
:
2671 intp
= va_arg (ap
, int *);
2672 *intp
= pwm
->needs_passphrase
;
2676 n
= va_arg (ap
, int);
2678 rc
= GPG_ERR_INV_VALUE
;
2680 pwm
->needs_passphrase
= n
;
2682 case PWMD_OPTION_TLS_VERIFY
:
2685 intp
= va_arg (ap
, int *);
2686 *intp
= pwm
->tls_verify
;
2690 n
= va_arg (ap
, int);
2692 rc
= GPG_ERR_INV_VALUE
;
2694 pwm
->tls_verify
= n
;
2696 case PWMD_OPTION_TLS_PRIORITY
:
2699 charpp
= va_arg (ap
, char **);
2700 *charpp
= pwm
->tls_priority
;
2704 pwmd_free (pwm
->tls_priority
);
2705 pwm
->tls_priority
= NULL
;
2706 arg1
= va_arg (ap
, char *);
2709 pwm
->tls_priority
= pwmd_strdup (arg1
);
2710 if (!pwm
->tls_priority
)
2711 rc
= GPG_ERR_ENOMEM
;
2714 case PWMD_OPTION_SOCKET_TIMEOUT
:
2717 intp
= va_arg (ap
, int *);
2718 *intp
= pwm
->socket_timeout
;
2722 n
= va_arg (ap
, int);
2725 rc
= GPG_ERR_INV_VALUE
;
2729 pwm
->socket_timeout
= n
;
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);
2740 if (pwm
->tcp
&& pwm
->tcp
->tls
&& pwm
->tcp
->tls
->session
)
2741 pwm
->tcp
->tls
->timeout
= pwm
->socket_timeout
;
2744 case PWMD_OPTION_READ_CB
:
2747 pwmd_read_cb_t
*cb
= va_arg (ap
, pwmd_read_cb_t
*);
2752 pwm
->read_cb
= va_arg (ap
, pwmd_read_cb_t
);
2754 case PWMD_OPTION_READ_CB_DATA
:
2757 void **data
= va_arg (ap
, void **);
2759 *data
= pwm
->read_cb_data
;
2763 pwm
->read_cb_data
= va_arg (ap
, void *);
2765 case PWMD_OPTION_WRITE_CB
:
2768 pwmd_write_cb_t
*cb
= va_arg (ap
, pwmd_write_cb_t
*);
2770 *cb
= pwm
->write_cb
;
2773 pwm
->write_cb
= va_arg (ap
, pwmd_write_cb_t
);
2775 case PWMD_OPTION_WRITE_CB_DATA
:
2778 void **data
= va_arg (ap
, void **);
2780 *data
= pwm
->write_cb_data
;
2784 pwm
->write_cb_data
= va_arg (ap
, void *);
2786 case PWMD_OPTION_OVERRIDE_INQUIRE
:
2789 intp
= va_arg (ap
, int *);
2790 *intp
= pwm
->override_inquire
;
2794 n
= va_arg (ap
, int);
2796 rc
= GPG_ERR_INV_VALUE
;
2798 pwm
->override_inquire
= n
;
2801 rc
= GPG_ERR_UNKNOWN_OPTION
;
2809 pwmd_setopt (pwm_t
* pwm
, int opt
, ...)
2815 rc
= pwmd_get_set_opt (pwm
, opt
, 0, ap
);
2821 pwmd_getopt (pwm_t
*pwm
, int opt
, ...)
2827 rc
= pwmd_get_set_opt (pwm
, opt
, 1, ap
);
2833 set_rcdefaults (pwm_t
*pwm
, char *filename
)
2837 char *line
= NULL
, *p
;
2838 unsigned line_n
= 0;
2842 if (!filename
&& isatty (STDIN_FILENO
))
2845 int err
= ttyname_r (STDOUT_FILENO
, buf
, sizeof (buf
));
2849 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, buf
);
2853 if (getenv ("TERM"))
2855 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, getenv ("TERM"));
2862 if (!filename
&& getenv ("DISPLAY"))
2864 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, getenv ("DISPLAY"));
2871 f
= pwmd_strdup ("libpwmd.conf");
2873 f
= _expand_homedir (filename
? filename
: (char *)"~/.config/libpwmd.conf",
2878 line
= pwmd_malloc (LINE_MAX
);
2881 fp
= fopen (f
, "r");
2890 rc
= GPG_ERR_ENOMEM
;
2893 rc
= GPG_ERR_ENOMEM
;
2902 while ((p
= fgets (line
, LINE_MAX
, fp
)))
2904 char name
[32] = {0}, val
[512] = {0};
2911 while (isspace (*p
))
2914 if (!*p
|| *p
== '#')
2917 if (p
[strlen (p
)-1] == '\n')
2918 p
[strlen (p
)-1] = 0;
2920 t
= strchr (p
, '=');
2923 fprintf(stderr
, N_("%s(%u): malformed line\n"), f
, line_n
);
2927 for (np
= name
; p
!= t
; p
++)
2929 if (++len
== sizeof (name
))
2938 while (isspace (*t
))
2941 while (isspace (*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
);
2979 fprintf(stderr
, N_("%s(%u): invalid option '%s', ignored.\n"), f
,
2993 pwmd_new (const char *name
, pwm_t
** pwm
)
2995 pwm_t
*h
= pwmd_calloc (1, sizeof (pwm_t
));
2999 return FINISH (GPG_ERR_ENOMEM
);
3003 h
->name
= pwmd_strdup (name
);
3007 return FINISH (GPG_ERR_ENOMEM
);
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;
3023 WSAStartup (0x202, &wsdata
);
3027 h
->opts
|= OPT_LOCK_ON_OPEN
;
3029 rc
= set_rcdefaults (h
, NULL
);
3042 pwmd_free (void *ptr
)
3048 pwmd_malloc (size_t size
)
3050 return _xmalloc (size
);
3054 pwmd_calloc (size_t nmemb
, size_t size
)
3056 return _xcalloc (nmemb
, size
);
3060 pwmd_realloc (void *ptr
, size_t size
)
3062 return _xrealloc (ptr
, size
);
3066 pwmd_strdup (const char *str
)
3073 t
= _xmalloc ((len
+ 1) * sizeof (char));
3077 for (c
= 0; c
< len
; c
++)
3085 pwmd_strdup_printf (const char *fmt
, ...)
3096 len
= vsnprintf (NULL
, 0, fmt
, ap
);
3098 buf
= pwmd_malloc (++len
);
3100 vsnprintf (buf
, len
, fmt
, ap2
);
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
);
3115 command_start (pwm
);
3116 if (which
== PWMD_PINENTRY_CONFIRM
&& pwm
->disable_pinentry
)
3118 rc
= get_password (pwm
, NULL
, NULL
, which
, 1);
3122 rc
= _pwmd_getpin (pwm
, filename
, result
, len
, which
);
3130 return LIBPWMD_VERSION_STR LIBPWMD_GIT_HASH
;
3138 #ifdef WITH_PINENTRY
3139 n
|= PWMD_FEATURE_PINENTRY
;
3142 n
|= PWMD_FEATURE_SSH
;
3145 n
|= PWMD_FEATURE_QUALITY
;
3148 n
|= PWMD_FEATURE_GNUTLS
;
3154 pwmd_fd (pwm_t
* pwm
, int *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
);
3167 pwmd_set_pointer (pwm_t
*pwm
, void *data
)
3169 pwm
->user_data
= data
;
3173 pwmd_get_pointer (pwm_t
*pwm
)
3175 return pwm
->user_data
;
3179 pwmd_gnutls_error (pwm_t
*pwm
, const char **str
)
3186 if (str
&& pwm
&& pwm
->tls_error
)
3187 *str
= gnutls_strerror (pwm
->tls_error
);
3189 return pwm
? pwm
->tls_error
: 0;
3194 pwmd_cancel (pwm_t
*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
)
3202 if (pwm
->fd
== ASSUAN_INVALID_FD
)
3204 return FINISH (GPG_ERR_INV_STATE
);
3206 /* Can only cancel the connection for the time being. */
3208 return FINISH (GPG_ERR_INV_STATE
);
3215 pwmd_test_quality (const char *str
, double *result
)
3217 #ifndef WITH_QUALITY
3220 return GPG_ERR_NOT_IMPLEMENTED
;
3223 return GPG_ERR_INV_ARG
;
3225 *result
= ZxcvbnMatch (str
, NULL
, NULL
);
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
)
3236 size_t len
= 0, n
= 0;
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
);
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
;
3262 for (i
= 0; cmdrc
[i
] != GPG_ERR_MISSING_ERRNO
; i
++)
3264 t
= pwmd_strdup_printf ("%u|%s", cmdrc
[i
], rcbuf
? rcbuf
: "");
3268 return FINISH (GPG_ERR_ENOMEM
);
3277 rcbuf
[strlen (rcbuf
)-1] = 0;
3278 t
= pwmd_strdup_printf ("2:rc%u:%s", strlen (rcbuf
), rcbuf
);
3281 return FINISH (GPG_ERR_ENOMEM
);
3284 n
+= strlen (rcbuf
);
3290 len
= strlen (*str
);
3292 if (offset
&& *offset
< len
)
3296 n
+= 2; // Parentheses for this sub-command
3298 s
= pwmd_malloc ((n
+ 1) * sizeof (char));
3302 return FINISH (GPG_ERR_ENOMEM
);
3306 if (with_rc
&& rcbuf
)
3308 memcpy (&s
[len
], rcbuf
, strlen (rcbuf
));
3309 len
+= strlen (rcbuf
);
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
);
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
);
3332 memcpy (&s
[len
], args
, argsize
);
3336 memcpy (&s
[len
++], ")", 1);
3340 n
= *str
? strlen (*str
) : 0;
3341 p
= pwmd_realloc (*str
, (n
+len
+1) * sizeof (char));
3345 return FINISH (GPG_ERR_ENOMEM
);
3350 memmove (&p
[*offset
+len
], &p
[*offset
], n
- *offset
);
3351 memcpy (&p
[*offset
], s
, len
);
3355 memcpy (&p
[n
], s
, len
);
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
,
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.
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
,
3392 pwmd_bulk_finalize (char **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));
3406 return FINISH (GPG_ERR_ENOMEM
);
3408 memmove (&p
[1], p
, slen
);
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
)
3423 gpg_error_t rrc
= 0;
3426 if (!str
|| !size
|| !id
|| !id_size
|| !offset
)
3427 return FINISH (GPG_ERR_INV_ARG
);
3441 if (strlen (str
) < 15 || memcmp (str
, "(11:bulk-result", 15))
3442 return FINISH (GPG_ERR_BAD_DATA
);
3455 if (size
- o
< 4 || memcmp (s
, "2:id", 4))
3456 return FINISH (GPG_ERR_NOT_FOUND
);
3462 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC
);
3465 while (isdigit (*s
))
3469 return FINISH (GPG_ERR_INV_SEXP
);
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
))
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
);
3495 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC
);
3498 len
= strtoul (s
, &e
, 10);
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
))
3509 return FINISH (GPG_ERR_INV_SEXP
);
3512 strncpy (buf
, s
, len
);
3514 if (len
> strlen (buf
))
3515 return FINISH (GPG_ERR_SEXP_STRING_TOO_LONG
);
3518 rrc
= strtoul (buf
, &e
, 10);
3520 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC
);
3527 len
= strtoul (s
, &e
, 10);
3529 return FINISH (GPG_ERR_SEXP_INV_LEN_SPEC
);
3531 while (isdigit (*s
))
3535 return FINISH (GPG_ERR_INV_SEXP
);
3540 // If no match, continue searching for the command id.
3557 return FINISH (GPG_ERR_NOT_FOUND
);