1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program 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
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
26 #include <sys/socket.h>
35 #include <sys/types.h>
37 #include <sys/select.h>
60 static gpg_error_t
send_pinentry_options(pwm_t
*pwm
);
61 static gpg_error_t
_pwmd_process(pwm_t
*pwm
);
62 static gpg_error_t
set_pinentry_retry(pwm_t
*pwm
);
63 static gpg_error_t
get_custom_passphrase(pwm_t
*pwm
, char **result
);
65 static const char *_pwmd_strerror(gpg_error_t e
)
67 gpg_err_code_t code
= gpg_err_code(e
);
69 if (code
>= GPG_ERR_USER_1
&& code
< gpg_err_code(EPWMD_MAX
)) {
74 return N_("Unknown error");
76 return N_("No cache slots available");
78 return N_("Recursion loop");
80 return N_("No file is open");
82 return N_("General LibXML error");
84 return N_("File modified");
91 const char *pwmd_strerror(gpg_error_t code
)
93 const char *p
= _pwmd_strerror(code
);
95 return p
? p
: gpg_strerror(code
);
98 int pwmd_strerror_r(gpg_error_t code
, char *buf
, size_t size
)
100 const char *p
= _pwmd_strerror(code
);
103 snprintf(buf
, size
, "%s", p
);
105 if (strlen(p
) > size
)
111 return gpg_strerror_r(code
, buf
, size
);
114 gpg_error_t
pwmd_init()
116 static int initialized
;
125 bindtextdomain("libpwmd", LOCALEDIR
);
128 assuan_set_malloc_hooks(pwmd_malloc
, pwmd_realloc
, pwmd_free
);
129 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT
);
134 gpg_error_t
_connect_finalize(pwm_t
*pwm
)
137 int n
= assuan_get_active_fds(pwm
->ctx
, 0, active
, N_ARRAY(active
));
142 return GPG_ERR_EBADFD
;
148 assuan_set_pointer(pwm
->ctx
, pwm
);
151 // Until X11 forwarding is supported, disable the remote pwmd pinentry.
153 rc
= pwmd_command(pwm
, NULL
, "OPTION PINENTRY=0");
161 rc
= pwmd_command(pwm
, NULL
, "OPTION CLIENT NAME=%s", pwm
->name
);
167 rc
= pwmd_command(pwm
, &result
, "VERSION");
169 if (rc
&& rc
!= GPG_ERR_ASS_UNKNOWN_CMD
)
173 pwm
->version
= PWMD_V1
;
175 pwm
->version
= PWMD_V2
;
181 static gpg_error_t
_pwmd_connect_url(pwm_t
*pwm
, const char *url
, int async
)
183 char *p
= (char *)url
;
187 return GPG_ERR_INV_ARG
;
189 if (!p
|| !strncmp(p
, "socket://", 9)) {
195 else if (!strncmp(p
, "ssh://", 6) || !strncmp(p
, "ssh6://", 7) ||
196 !strncmp(p
, "ssh4://", 7)) {
198 return GPG_ERR_NOT_IMPLEMENTED
;
202 char *identity
= NULL
;
203 char *known_hosts
= NULL
;
204 char *username
= NULL
;
206 if (!strncmp(p
, "ssh6://", 7)) {
207 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV6
);
210 else if (!strncmp(p
, "ssh4://", 7)) {
211 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV4
);
215 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IP_ANY
);
222 rc
= _parse_ssh_url(p
, &host
, &port
, &username
, &identity
,
229 rc
= pwmd_ssh_connect_async(pwm
, host
, port
, identity
, username
,
232 rc
= pwmd_ssh_connect(pwm
, host
, port
, identity
, username
,
246 pwmd_free(known_hosts
);
253 rc
= pwmd_connect(pwm
, p
);
254 pwm
->state
= ASYNC_DONE
;
258 gpg_error_t
pwmd_connect_url(pwm_t
*pwm
, const char *url
)
260 return _pwmd_connect_url(pwm
, url
, 0);
263 gpg_error_t
pwmd_connect_url_async(pwm_t
*pwm
, const char *url
)
265 return _pwmd_connect_url(pwm
, url
, 1);
268 gpg_error_t
pwmd_connect(pwm_t
*pwm
, const char *path
)
270 char *socketpath
= NULL
;
271 assuan_context_t ctx
;
277 return GPG_ERR_INV_ARG
;
279 pwbuf
= _getpwuid(&pw
);
282 return gpg_error_from_errno(errno
);
285 socketpath
= pwmd_strdup_printf("%s/.pwmd/socket", pw
.pw_dir
);
287 socketpath
= _expand_homedir((char *)path
, &pw
);
292 return gpg_error_from_errno(ENOMEM
);
294 rc
= assuan_socket_connect_ext(&ctx
, socketpath
, -1, 0);
295 pwmd_free(socketpath
);
298 return gpg_err_code(rc
);
301 return _connect_finalize(pwm
);
304 static void disconnect(pwm_t
*pwm
)
306 if (!pwm
|| !pwm
->ctx
)
309 assuan_disconnect(pwm
->ctx
);
314 void pwmd_close(pwm_t
*pwm
)
322 pwmd_free(pwm
->password
);
325 pwmd_free(pwm
->title
);
328 pwmd_free(pwm
->desc
);
331 pwmd_free(pwm
->prompt
);
333 if (pwm
->pinentry_tty
)
334 pwmd_free(pwm
->pinentry_tty
);
336 if (pwm
->pinentry_display
)
337 pwmd_free(pwm
->pinentry_display
);
339 if (pwm
->pinentry_term
)
340 pwmd_free(pwm
->pinentry_term
);
343 pwmd_free(pwm
->lcctype
);
346 pwmd_free(pwm
->lcmessages
);
349 pwmd_free(pwm
->filename
);
352 pwmd_free(pwm
->name
);
356 _free_ssh_conn(pwm
->tcp_conn
);
361 _pinentry_disconnect(pwm
);
367 gpg_error_t
pwmd_ssh_connect_async(pwm_t
*pwm
, const char *host
, int port
,
368 const char *identity
, const char *user
, const char *known_hosts
)
371 return GPG_ERR_NOT_IMPLEMENTED
;
373 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, identity
, user
,
374 known_hosts
, ASYNC_CMD_CONNECT
);
378 gpg_error_t
pwmd_ssh_connect(pwm_t
*pwm
, const char *host
, int port
,
379 const char *identity
, const char *user
, const char *known_hosts
)
382 return GPG_ERR_NOT_IMPLEMENTED
;
384 return _do_pwmd_ssh_connect(pwm
, host
, port
, identity
, user
, known_hosts
, 0);
388 gpg_error_t
pwmd_get_hostkey(pwm_t
*pwm
, const char *host
, int port
,
392 return GPG_ERR_NOT_IMPLEMENTED
;
397 rc
= _do_pwmd_ssh_connect(pwm
, host
, port
, NULL
, NULL
, NULL
, 1);
402 hostkey
= pwmd_strdup(pwm
->tcp_conn
->hostkey
);
405 rc
= gpg_error_from_errno(ENOMEM
);
412 gpg_error_t
pwmd_get_hostkey_async(pwm_t
*pwm
, const char *host
, int port
)
415 return GPG_ERR_NOT_IMPLEMENTED
;
417 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, NULL
, NULL
, NULL
,
422 static int inquire_realloc_cb(void *data
, const void *buffer
, size_t len
)
424 membuf_t
*mem
= (membuf_t
*)data
;
430 if ((p
= pwmd_realloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
431 return gpg_error_from_errno(ENOMEM
);
434 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
439 static int inquire_cb(void *data
, const char *keyword
)
441 pwm_t
*pwm
= (pwm_t
*)data
;
443 int flags
= fcntl(pwm
->fd
, F_GETFL
);
445 /* Shouldn't get this far without a callback. */
446 if (!pwm
->inquire_func
)
447 return GPG_ERR_INV_ARG
;
454 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
, &result
, &len
);
455 rc
= gpg_err_code(rc
);
457 if (rc
== GPG_ERR_EOF
|| !rc
) {
458 if (len
<= 0 || !result
) {
463 arc
= assuan_send_data(pwm
->ctx
, result
, len
);
464 arc
= gpg_err_code(arc
);
466 if (rc
== GPG_ERR_EOF
) {
477 /* Set to non-blocking so _pwmd_process() can return. */
478 fcntl(pwm
->fd
, F_SETFL
, O_NONBLOCK
);
479 rc
= _pwmd_process(pwm
);
480 fcntl(pwm
->fd
, F_SETFL
, flags
);
484 fcntl(pwm
->fd
, F_SETFL
, flags
);
485 return gpg_err_code(rc
);
488 static gpg_error_t
do_nb_command(pwm_t
*pwm
, const char *cmd
, ...)
495 if (pwm
->state
== ASYNC_DONE
)
496 pwm
->state
= ASYNC_INIT
;
498 if (pwm
->state
!= ASYNC_INIT
)
499 return GPG_ERR_INV_STATE
;
501 buf
= pwmd_malloc(ASSUAN_LINELENGTH
+1);
504 return gpg_error_from_errno(ENOMEM
);
507 len
= vsnprintf(buf
, ASSUAN_LINELENGTH
+1, cmd
, ap
);
510 if (len
>= ASSUAN_LINELENGTH
+1) {
512 return GPG_ERR_LINE_TOO_LONG
;
515 rc
= assuan_write_line(pwm
->ctx
, buf
);
519 pwm
->state
= ASYNC_PROCESS
;
521 return gpg_err_code(rc
);
524 gpg_error_t
pwmd_open_async(pwm_t
*pwm
, const char *filename
)
527 const char *f
= NULL
;
530 if (!pwm
|| !filename
)
531 return GPG_ERR_INV_ARG
;
534 return GPG_ERR_INV_STATE
;
536 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
537 return GPG_ERR_ASS_NESTED_COMMANDS
;
539 if (pwm
->lastcmd
== ASYNC_CMD_NONE
) {
543 pwmd_free(pwm
->filename
);
545 pwm
->filename
= pwmd_strdup(filename
);
548 return gpg_error_from_errno(ENOMEM
);
550 gpg_error_t rc
= send_pinentry_options(pwm
);
555 rc
= get_custom_passphrase(pwm
, &p
);
557 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
563 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN2
) {
568 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN
) {
569 rc
= set_pinentry_retry(pwm
);
578 return GPG_ERR_INV_STATE
;
580 pwm
->cmd
= ASYNC_CMD_OPEN
;
581 return do_nb_command(pwm
, "OPEN %s %s", f
, p
? p
: "");
584 gpg_error_t
pwmd_save_async(pwm_t
*pwm
)
589 return GPG_ERR_INV_ARG
;
592 return GPG_ERR_INV_STATE
;
594 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
595 return GPG_ERR_ASS_NESTED_COMMANDS
;
597 if (pwm
->lastcmd
!= ASYNC_CMD_SAVE2
) {
598 gpg_error_t rc
= send_pinentry_options(pwm
);
603 rc
= get_custom_passphrase(pwm
, &p
);
605 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
613 pwm
->cmd
= ASYNC_CMD_SAVE
;
614 return do_nb_command(pwm
, "SAVE %s", p
? p
: "");
617 static gpg_error_t
parse_assuan_line(pwm_t
*pwm
)
623 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
626 if (line
[0] == 'O' && line
[1] == 'K' &&
627 (line
[2] == 0 || line
[2] == ' ')) {
628 pwm
->state
= ASYNC_DONE
;
630 else if (line
[0] == '#') {
632 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' ')) {
633 if (pwm
->status_func
) {
634 rc
= pwm
->status_func(pwm
->status_data
,
635 line
[1] == 0 ? line
+1 : line
+2);
638 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
639 (line
[3] == 0 || line
[3] == ' ')) {
642 pwm
->state
= ASYNC_DONE
;
646 return gpg_err_code(rc
);
649 gpg_error_t
pwmd_pending_line(pwm_t
*pwm
)
652 return GPG_ERR_INV_ARG
;
655 return GPG_ERR_INV_STATE
;
657 return assuan_pending_line(pwm
->ctx
) ? 0 : GPG_ERR_NO_DATA
;
660 static pwmd_async_t
reset_async(pwm_t
*pwm
, int done
)
662 pwm
->state
= ASYNC_INIT
;
663 pwm
->cmd
= pwm
->lastcmd
= ASYNC_CMD_NONE
;
666 if (pwm
->nb_fd
!= -1) {
671 if (pwm
->_password
) {
672 pwmd_free(pwm
->_password
);
673 pwm
->_password
= NULL
;
677 if (done
&& pwm
->tcp_conn
) {
678 _free_ssh_conn(pwm
->tcp_conn
);
679 pwm
->tcp_conn
= NULL
;
687 * Used for processing status messages when not in an async command and for
688 * waiting for the result from pwmd_open_async() and pwmd_save_async().
690 static gpg_error_t
_pwmd_process(pwm_t
*pwm
)
694 struct timeval tv
= {0, 0};
698 FD_SET(pwm
->fd
, &fds
);
700 n
= pth_select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
702 n
= select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
706 return gpg_error_from_syserror();
709 if (FD_ISSET(pwm
->fd
, &fds
))
710 rc
= parse_assuan_line(pwm
);
713 while (!rc
&& assuan_pending_line(pwm
->ctx
))
714 rc
= parse_assuan_line(pwm
);
716 return gpg_err_code(rc
);
719 static void reset_handle(pwm_t
*h
)
724 _pinentry_disconnect(h
);
732 gpg_error_t
pwmd_disconnect(pwm_t
*pwm
)
735 return GPG_ERR_INV_ARG
;
738 if (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1)
742 return GPG_ERR_INV_STATE
;
748 _ssh_disconnect(pwm
);
755 pwmd_async_t
pwmd_process(pwm_t
*pwm
, gpg_error_t
*rc
, char **result
)
757 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
760 struct timeval tv
= {0, 0};
767 return GPG_ERR_INV_ARG
;
772 *rc
= GPG_ERR_INV_ARG
;
775 else if (!pwm
->ctx
) {
778 *rc
= GPG_ERR_INV_STATE
;
782 case ASYNC_CMD_CONNECT
:
783 case ASYNC_CMD_HOSTKEY
:
789 /* When not in a command, this will let libassuan process status messages
790 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
791 * descriptor returned by pwmd_get_fd() to determine when this should be
792 * called or call pwmd_pending_line() to determine whether a buffered line
793 * needs to be processed. */
794 if (pwm
->cmd
== ASYNC_CMD_NONE
) {
795 *rc
= _pwmd_process(pwm
);
799 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
800 if (pwm
->state
== ASYNC_DONE
) {
801 *rc
= _pwmd_process(pwm
);
802 return reset_async(pwm
, 0);
805 if (pwm
->state
!= ASYNC_PROCESS
) {
806 *rc
= GPG_ERR_INV_STATE
;
811 if (pwm
->cmd
== ASYNC_CMD_DNS
) {
814 if (pwm
->tcp_conn
->rc
) {
815 *rc
= pwm
->tcp_conn
->rc
;
816 return reset_async(pwm
, 1);
821 n
= ares_fds(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
823 /* Shouldn't happen. */
828 n
= pth_select(n
, &rfds
, &wfds
, NULL
, &tv
);
830 n
= select(n
, &rfds
, &wfds
, NULL
, &tv
);
834 *rc
= gpg_error_from_syserror();
835 return reset_async(pwm
, 1);
839 ares_process(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
843 else if (pwm
->cmd
== ASYNC_CMD_CONNECT
) {
844 if (pwm
->tcp_conn
->rc
== GPG_ERR_EINPROGRESS
) {
846 socklen_t len
= sizeof(int);
849 FD_SET(pwm
->tcp_conn
->fd
, &fds
);
851 n
= pth_select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
853 n
= select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
856 if (!n
|| !FD_ISSET(pwm
->tcp_conn
->fd
, &fds
))
859 *rc
= gpg_error_from_syserror();
860 return reset_async(pwm
, 1);
863 ret
= getsockopt(pwm
->tcp_conn
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
866 *rc
= ret
? gpg_error_from_syserror() : gpg_error_from_errno(n
);
867 return reset_async(pwm
, 1);
870 else if (pwm
->tcp_conn
->rc
) {
871 *rc
= pwm
->tcp_conn
->rc
;
872 return reset_async(pwm
, 1);
875 fcntl(pwm
->tcp_conn
->fd
, F_SETFL
, 0);
876 *rc
= _setup_ssh_session(pwm
);
879 switch (pwm
->tcp_conn
->cmd
) {
880 case ASYNC_CMD_HOSTKEY
:
881 *result
= pwm
->result
;
888 return reset_async(pwm
, *rc
? 1 : 0);
893 if (pwm
->cmd
== ASYNC_CMD_OPEN2
|| pwm
->cmd
== ASYNC_CMD_SAVE2
) {
896 if (pwm
->nb_fd
== -1) {
897 *rc
= GPG_ERR_INV_STATE
;
898 return reset_async(pwm
, 0);
902 FD_SET(pwm
->nb_fd
, &fds
);
903 FD_SET(pwm
->fd
, &fds
);
905 n
= pth_select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
907 n
= select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
910 *rc
= gpg_error_from_syserror();
911 return reset_async(pwm
, 0);
914 if (n
> 0 && FD_ISSET(pwm
->nb_fd
, &fds
)) {
917 size_t len
= pth_read(pwm
->nb_fd
, &nb
, sizeof(nb
));
919 size_t len
= read(pwm
->nb_fd
, &nb
, sizeof(nb
));
921 waitpid(pwm
->nb_pid
, &status
, WNOHANG
);
923 if (len
!= sizeof(nb
)) {
924 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
925 *rc
= gpg_error_from_syserror();
926 return reset_async(pwm
, 0);
932 return reset_async(pwm
, 0);
934 /* Since the non-blocking pinentry returned a success, do a
935 * non-blocking OPEN or SAVE. */
936 pwmd_async_cmd_t c
= pwm
->cmd
;
938 pwm
->_password
= pwmd_strdup(nb
.password
);
939 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
942 if (!pwm
->_password
) {
943 *rc
= gpg_error_from_errno(ENOMEM
);
944 return reset_async(pwm
, 0);
947 if (c
== ASYNC_CMD_SAVE2
)
948 *rc
= pwmd_save_async(pwm
);
950 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
957 return ASYNC_PROCESS
;
960 /* Fall through so status messages can be processed during the
966 *rc
= GPG_ERR_INV_STATE
;
967 return reset_async(pwm
, 0);
970 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
972 *rc
= _pwmd_process(pwm
);
974 if (*rc
&& *rc
!= GPG_ERR_INV_PASSPHRASE
)
975 return reset_async(pwm
, 0);
977 if (pwm
->cmd
== ASYNC_CMD_OPEN
&&
978 *rc
== GPG_ERR_INV_PASSPHRASE
&&
980 (!pwm
->tcp_conn
|| (pwm
->tcp_conn
&& pwm
->lastcmd
== ASYNC_CMD_OPEN2
)) &&
982 ++pwm
->pin_try
< pwm
->pinentry_tries
) {
983 if (!get_custom_passphrase(pwm
, NULL
))
987 if (pwm
->_password
) {
989 pwm
->lastcmd
= ASYNC_CMD_OPEN2
;
990 *rc
= pwmd_open_async2(pwm
, pwm
->filename
);
995 pwm
->lastcmd
= ASYNC_CMD_OPEN
;
996 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
1003 if (*rc
|| pwm
->state
== ASYNC_DONE
)
1004 return reset_async(pwm
, 0);
1009 gpg_error_t
_assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
1010 char **result
, const char *cmd
)
1016 return GPG_ERR_INV_ARG
;
1018 if (strlen(cmd
) >= ASSUAN_LINELENGTH
+1)
1019 return GPG_ERR_LINE_TOO_LONG
;
1023 rc
= assuan_transact(ctx
, cmd
, inquire_realloc_cb
, &data
,
1025 pwm
->pctx
== ctx
? pwm
->_inquire_func
: inquire_cb
,
1026 pwm
->pctx
== ctx
? pwm
->_inquire_data
: pwm
,
1030 pwm
->status_func
, pwm
->status_data
);
1034 pwmd_free(data
.buf
);
1040 inquire_realloc_cb(&data
, "", 1);
1043 pwmd_free(data
.buf
);
1044 rc
= GPG_ERR_INV_ARG
;
1047 *result
= (char *)data
.buf
;
1051 return gpg_err_code(rc
);
1054 gpg_error_t
pwmd_inquire(pwm_t
*pwm
, const char *cmd
, pwmd_inquire_cb_t fn
,
1057 if (!pwm
|| !cmd
|| !fn
)
1058 return GPG_ERR_INV_ARG
;
1061 return GPG_ERR_INV_STATE
;
1063 pwm
->inquire_func
= fn
;
1064 pwm
->inquire_data
= data
;
1065 return _assuan_command(pwm
, pwm
->ctx
, NULL
, cmd
);
1068 gpg_error_t
pwmd_command_ap(pwm_t
*pwm
, char **result
, const char *cmd
,
1076 return GPG_ERR_INV_ARG
;
1079 return GPG_ERR_INV_STATE
;
1082 * C99 allows the dst pointer to be null which will calculate the length
1083 * of the would-be result and return it.
1086 len
= vsnprintf(NULL
, 0, cmd
, ap
)+1;
1087 buf
= (char *)pwmd_malloc(len
);
1091 return gpg_error_from_errno(ENOMEM
);
1094 len
= vsnprintf(buf
, len
, cmd
, ap2
);
1097 if (buf
[strlen(buf
)-1] == '\n')
1098 buf
[strlen(buf
)-1] = 0;
1100 if (buf
[strlen(buf
)-1] == '\r')
1101 buf
[strlen(buf
)-1] = 0;
1103 gpg_error_t rc
= _assuan_command(pwm
, pwm
->ctx
, result
, buf
);
1108 gpg_error_t
pwmd_command(pwm_t
*pwm
, char **result
, const char *cmd
, ...)
1113 return GPG_ERR_INV_ARG
;
1116 return GPG_ERR_INV_STATE
;
1122 gpg_error_t rc
= pwmd_command_ap(pwm
, result
, cmd
, ap
);
1127 static gpg_error_t
send_pinentry_options(pwm_t
*pwm
)
1131 if (pwm
->pinentry_path
) {
1132 rc
= pwmd_command(pwm
, NULL
, "OPTION PATH=%s", pwm
->pinentry_path
);
1138 if (pwm
->pinentry_tty
) {
1139 rc
= pwmd_command(pwm
, NULL
, "OPTION TTYNAME=%s", pwm
->pinentry_tty
);
1145 if (pwm
->pinentry_term
) {
1146 rc
= pwmd_command(pwm
, NULL
, "OPTION TTYTYPE=%s", pwm
->pinentry_term
);
1152 if (pwm
->pinentry_display
) {
1153 rc
= pwmd_command(pwm
, NULL
, "OPTION DISPLAY=%s",
1154 pwm
->pinentry_display
);
1161 rc
= pwmd_command(pwm
, NULL
, "OPTION TITLE=%s", pwm
->title
);
1168 rc
= pwmd_command(pwm
, NULL
, "OPTION DESC=%s", pwm
->desc
);
1175 rc
= pwmd_command(pwm
, NULL
, "OPTION PROMPT=%s", pwm
->prompt
);
1182 rc
= pwmd_command(pwm
, NULL
, "OPTION LC_CTYPE=%s", pwm
->lcctype
);
1188 if (pwm
->lcmessages
) {
1189 rc
= pwmd_command(pwm
, NULL
, "OPTION LC_MESSAGES=%s", pwm
->lcmessages
);
1195 if (pwm
->pinentry_timeout
>= 0 && !pwm
->pin_try
) {
1196 rc
= pwmd_command(pwm
, NULL
, "OPTION TIMEOUT=%i", pwm
->pinentry_timeout
);
1205 gpg_error_t
pwmd_socket_type(pwm_t
*pwm
, pwmd_socket_t
*result
)
1207 if (!pwm
|| !result
)
1208 return GPG_ERR_INV_ARG
;
1211 if (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1)
1215 return GPG_ERR_INV_STATE
;
1218 *result
= pwm
->tcp_conn
? PWMD_SOCKET_SSH
: PWMD_SOCKET_UDS
;
1220 *result
= PWMD_SOCKET_UDS
;
1225 static gpg_error_t
set_pinentry_retry(pwm_t
*pwm
)
1229 if (pwm
->pin_try
== 1) {
1230 rc
= pwmd_command(pwm
, NULL
, "OPTION TITLE=%s",
1231 N_("Invalid passphrase, please try again."));
1236 rc
= pwmd_command(pwm
, NULL
, "OPTION TIMEOUT=0");
1242 static gpg_error_t
get_custom_passphrase(pwm_t
*pwm
, char **result
)
1244 gpg_error_t rc
= GPG_ERR_NO_DATA
;
1249 if (pwm
->password
|| pwm
->passfunc
)
1253 if (pwm
->password
) {
1255 *result
= pwm
->password
;
1257 else if (pwm
->passfunc
)
1258 rc
= pwm
->passfunc(pwm
->passdata
, result
);
1263 static gpg_error_t
do_pwmd_open(pwm_t
*pwm
, const char *filename
, int nb
,
1266 char *result
= NULL
;
1267 char *password
= NULL
;
1271 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1274 if (!pwm
|| !filename
|| !*filename
)
1275 return GPG_ERR_INV_ARG
;
1278 return GPG_ERR_INV_STATE
;
1281 * Avoid calling pinentry if the password is cached on the server or if
1282 * this is a new file. pwmd version 2 adds a VERSION command which is
1283 * determined in _connect_finalize(). If the server is version 2,
1284 * ISCACHED will return GPG_ERR_ENOENT if it doesn't exist.
1287 /* Don't try a local filesystem lookup of the data file over a remote
1289 if (!pwm
->tcp_conn
&& pwm
->version
== PWMD_V1
) {
1291 if (pwm
->version
== PWMD_V1
) {
1293 rc
= pwmd_command(pwm
, &result
, "GETCONFIG data_directory");
1298 path
= pwmd_strdup_printf("%s/%s", result
, filename
);
1302 return gpg_error_from_errno(ENOMEM
);
1304 if (access(path
, R_OK
) == -1) {
1305 if (errno
== ENOENT
) {
1314 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", filename
);
1316 /* pwmd >= 2.0 specific. This is a new file which doesn't require a
1318 if (rc
== GPG_ERR_ENOENT
)
1321 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1324 if (rc
== GPG_ERR_NOT_FOUND
) {
1325 rc
= get_custom_passphrase(pwm
, &password
);
1327 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
1329 else if (rc
== GPG_ERR_NO_DATA
)
1330 rc
= GPG_ERR_NOT_FOUND
;
1335 #ifdef WITH_PINENTRY
1336 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1337 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1338 if (!pwm
->pin_try
) {
1339 rc
= pwmd_command(pwm
, NULL
, "OPTION PINENTRY=0");
1345 rc
= _pinentry_open(pwm
, filename
, &password
, nb
);
1347 /* pwmd_process() should be called if using a non-blocking local
1349 if (rc
|| (!rc
&& nb
))
1355 reset_async(pwm
, 0);
1358 if (!local_pinentry
&& !pwm
->tcp_conn
&& !pwm
->pin_try
) {
1360 if (!local_pinentry
&& !pwm
->pin_try
) {
1362 rc
= send_pinentry_options(pwm
);
1368 rc
= pwmd_command(pwm
, NULL
, "OPEN %s %s", filename
,
1369 password
? password
: "");
1372 * Keep the user defined password set with pwmd_setopt(). The password may
1373 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1375 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1376 pwmd_free(password
);
1378 if (rc
== GPG_ERR_INV_PASSPHRASE
) {
1379 if (++pwm
->pin_try
< pwm
->pinentry_tries
) {
1380 if (!get_custom_passphrase(pwm
, NULL
))
1383 #ifdef WITH_PINENTRY
1385 if (pwm
->tcp_conn
&& !local_pinentry
)
1387 else if (local_pinentry
)
1388 rc
= _getpin(pwm
, &password
, PWMD_PINENTRY_OPEN_FAILED
);
1392 rc
= _getpin(pwm
, &password
, PWMD_PINENTRY_OPEN_FAILED
);
1402 rc
= set_pinentry_retry(pwm
);
1409 #ifdef WITH_PINENTRY
1410 else if (local_pinentry
)
1411 _pinentry_disconnect(pwm
);
1417 #ifdef WITH_PINENTRY
1418 else if (rc
&& local_pinentry
)
1419 _pinentry_disconnect(pwm
);
1424 pwmd_free(pwm
->filename
);
1426 pwm
->filename
= pwmd_strdup(filename
);
1432 gpg_error_t
pwmd_open2(pwm_t
*pwm
, const char *filename
)
1434 #ifndef WITH_PINENTRY
1435 return GPG_ERR_NOT_IMPLEMENTED
;
1437 return do_pwmd_open(pwm
, filename
, 0, 1);
1441 gpg_error_t
pwmd_open(pwm_t
*pwm
, const char *filename
)
1443 return do_pwmd_open(pwm
, filename
, 0, 0);
1446 gpg_error_t
pwmd_open_async2(pwm_t
*pwm
, const char *filename
)
1448 #ifndef WITH_PINENTRY
1449 return GPG_ERR_NOT_IMPLEMENTED
;
1451 if (!pwm
|| !filename
)
1452 return GPG_ERR_INV_ARG
;
1455 return GPG_ERR_INV_STATE
;
1457 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1458 return GPG_ERR_ASS_NESTED_COMMANDS
;
1460 /* Initialize a new command since this is not a pinentry retry. */
1461 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1464 pwm
->cmd
= ASYNC_CMD_OPEN2
;
1465 pwm
->state
= ASYNC_PROCESS
;
1466 gpg_error_t rc
= do_pwmd_open(pwm
, filename
, 1, 1);
1469 reset_async(pwm
, 0);
1475 static gpg_error_t
do_pwmd_save(pwm_t
*pwm
, int nb
, int local_pinentry
)
1477 char *result
= NULL
;
1478 char *password
= NULL
;
1482 return GPG_ERR_INV_ARG
;
1485 return GPG_ERR_INV_STATE
;
1487 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", pwm
->filename
);
1489 if (rc
== GPG_ERR_ENOENT
)
1490 rc
= GPG_ERR_NOT_FOUND
;
1492 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1495 if (rc
== GPG_ERR_NOT_FOUND
) {
1496 rc
= get_custom_passphrase(pwm
, &password
);
1498 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
1500 else if (rc
== GPG_ERR_NO_DATA
)
1501 rc
= GPG_ERR_NOT_FOUND
;
1506 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1507 #ifdef WITH_PINENTRY
1508 /* Get the password using the LOCAL pinentry. */
1512 pwmd_nb_status_t pw
;
1515 return gpg_error_from_syserror();
1528 pw
.error
= _do_save_getpin(pwm
, &password
);
1531 snprintf(pw
.password
, sizeof(pw
.password
), "%s",
1533 pwmd_free(password
);
1536 pth_write(p
[1], &pw
, sizeof(pw
));
1538 write(p
[1], &pw
, sizeof(pw
));
1540 memset(&pw
, 0, sizeof(pw
));
1545 rc
= gpg_error_from_syserror();
1559 rc
= _do_save_getpin(pwm
, &password
);
1566 pwm
->state
= ASYNC_DONE
;
1569 reset_async(pwm
, 0);
1572 if (!local_pinentry
&& !pwm
->tcp_conn
) {
1574 if (!local_pinentry
) {
1576 rc
= send_pinentry_options(pwm
);
1582 rc
= pwmd_command(pwm
, NULL
, "SAVE %s", password
? password
: "");
1584 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1585 pwmd_free(password
);
1590 gpg_error_t
pwmd_save_async2(pwm_t
*pwm
)
1592 #ifndef WITH_PINENTRY
1593 return GPG_ERR_NOT_IMPLEMENTED
;
1596 return GPG_ERR_INV_ARG
;
1599 return GPG_ERR_INV_STATE
;
1601 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1602 return GPG_ERR_ASS_NESTED_COMMANDS
;
1604 pwm
->cmd
= ASYNC_CMD_SAVE2
;
1605 pwm
->state
= ASYNC_PROCESS
;
1606 gpg_error_t rc
= do_pwmd_save(pwm
, 1, 1);
1609 reset_async(pwm
, 0);
1615 gpg_error_t
pwmd_save2(pwm_t
*pwm
)
1617 #ifndef WITH_PINENTRY
1618 return GPG_ERR_NOT_IMPLEMENTED
;
1620 return do_pwmd_save(pwm
, 0, 1);
1624 gpg_error_t
pwmd_save(pwm_t
*pwm
)
1626 return do_pwmd_save(pwm
, 0, 0);
1629 gpg_error_t
pwmd_setopt(pwm_t
*pwm
, pwmd_option_t opt
, ...)
1632 int n
= va_arg(ap
, int);
1637 return GPG_ERR_INV_ARG
;
1642 case PWMD_OPTION_STATUS_CB
:
1643 pwm
->status_func
= va_arg(ap
, pwmd_status_cb_t
);
1645 case PWMD_OPTION_STATUS_DATA
:
1646 pwm
->status_data
= va_arg(ap
, void *);
1648 case PWMD_OPTION_PASSPHRASE_CB
:
1649 pwm
->passfunc
= va_arg(ap
, pwmd_passphrase_cb_t
);
1651 case PWMD_OPTION_PASSPHRASE_DATA
:
1652 pwm
->passdata
= va_arg(ap
, void *);
1654 case PWMD_OPTION_PASSPHRASE
:
1655 arg1
= va_arg(ap
, char *);
1658 pwmd_free(pwm
->password
);
1660 pwm
->password
= pwmd_strdup(arg1
);
1662 case PWMD_OPTION_PINENTRY_TRIES
:
1663 n
= va_arg(ap
, int);
1667 rc
= GPG_ERR_INV_VALUE
;
1670 pwm
->pinentry_tries
= n
;
1672 case PWMD_OPTION_PINENTRY_TIMEOUT
:
1673 n
= va_arg(ap
, int);
1677 rc
= GPG_ERR_INV_VALUE
;
1680 pwm
->pinentry_timeout
= n
;
1682 case PWMD_OPTION_PINENTRY_PATH
:
1683 if (pwm
->pinentry_path
)
1684 pwmd_free(pwm
->pinentry_path
);
1686 pwm
->pinentry_path
= _expand_homedir(va_arg(ap
, char *), NULL
);
1688 case PWMD_OPTION_PINENTRY_TTY
:
1689 if (pwm
->pinentry_tty
)
1690 pwmd_free(pwm
->pinentry_tty
);
1692 pwm
->pinentry_tty
= pwmd_strdup(va_arg(ap
, char *));
1694 case PWMD_OPTION_PINENTRY_DISPLAY
:
1695 if (pwm
->pinentry_display
)
1696 pwmd_free(pwm
->pinentry_display
);
1698 pwm
->pinentry_display
= pwmd_strdup(va_arg(ap
, char *));
1700 case PWMD_OPTION_PINENTRY_TERM
:
1701 if (pwm
->pinentry_term
)
1702 pwmd_free(pwm
->pinentry_term
);
1704 pwm
->pinentry_term
= pwmd_strdup(va_arg(ap
, char *));
1706 case PWMD_OPTION_PINENTRY_TITLE
:
1708 pwmd_free(pwm
->title
);
1710 pwm
->title
= _percent_escape(va_arg(ap
, char *));
1712 case PWMD_OPTION_PINENTRY_PROMPT
:
1714 pwmd_free(pwm
->prompt
);
1716 pwm
->prompt
= _percent_escape(va_arg(ap
, char *));
1718 case PWMD_OPTION_PINENTRY_DESC
:
1720 pwmd_free(pwm
->desc
);
1722 pwm
->desc
= _percent_escape(va_arg(ap
, char *));
1724 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
1726 pwmd_free(pwm
->lcctype
);
1728 pwm
->lcctype
= pwmd_strdup(va_arg(ap
, char *));
1730 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
1731 if (pwm
->lcmessages
)
1732 pwmd_free(pwm
->lcmessages
);
1734 pwm
->lcmessages
= pwmd_strdup(va_arg(ap
, char *));
1736 case PWMD_OPTION_IP_VERSION
:
1738 n
= va_arg(ap
, int);
1747 rc
= GPG_ERR_INV_VALUE
;
1753 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1757 rc
= GPG_ERR_UNKNOWN_OPTION
;
1765 gpg_error_t
pwmd_get_fds(pwm_t
*pwm
, pwmd_fd_t
*fds
, int *n_fds
)
1770 int afds
[ARES_GETSOCK_MAXNUM
];
1775 if (!pwm
|| !fds
|| !n_fds
|| *n_fds
<= 0)
1776 return GPG_ERR_INV_ARG
;
1780 memset(afds
, 0, sizeof(int)*ARES_GETSOCK_MAXNUM
);
1782 memset(fds
, 0, sizeof(pwmd_fd_t
)*in_total
);
1787 case ASYNC_CMD_NONE
:
1788 case ASYNC_CMD_OPEN
:
1789 case ASYNC_CMD_SAVE
:
1790 #ifdef WITH_PINENTRY
1794 return GPG_ERR_INV_STATE
;
1797 fds
[fd
].fd
= pwm
->fd
;
1798 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1800 #ifdef WITH_PINENTRY
1801 case ASYNC_CMD_OPEN2
:
1802 case ASYNC_CMD_SAVE2
:
1803 /* The command has already completed (cached or new). */
1804 if (pwm
->state
== ASYNC_DONE
)
1807 if (pwm
->nb_fd
== -1)
1808 return GPG_ERR_INV_STATE
;
1811 fds
[fd
].fd
= pwm
->nb_fd
;
1812 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1817 if (!pwm
->tcp_conn
|| !pwm
->tcp_conn
->chan
)
1818 return GPG_ERR_INV_STATE
;
1820 n
= ares_getsock(pwm
->tcp_conn
->chan
, afds
, ARES_GETSOCK_MAXNUM
);
1822 for (i
= 0; i
< ARES_GETSOCK_MAXNUM
; i
++) {
1825 if (fd
> in_total
) {
1827 return GPG_ERR_ERANGE
;
1830 if (ARES_GETSOCK_READABLE(n
, i
)) {
1832 fds
[fd
].flags
|= PWMD_FD_READABLE
;
1835 if (ARES_GETSOCK_WRITABLE(n
, i
)) {
1837 fds
[fd
].flags
|= PWMD_FD_WRITABLE
;
1841 fds
[fd
++].fd
= afds
[i
];
1846 case ASYNC_CMD_CONNECT
:
1847 case ASYNC_CMD_HOSTKEY
:
1848 if (!pwm
->tcp_conn
|| pwm
->tcp_conn
->fd
== -1)
1849 return GPG_ERR_INV_STATE
;
1852 fds
[fd
].fd
= pwm
->tcp_conn
->fd
;
1853 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1858 return GPG_ERR_INV_STATE
;
1861 pwm_t
*pwmd_new(const char *name
)
1863 pwm_t
*h
= pwmd_calloc(1, sizeof(pwm_t
));
1869 h
->name
= pwmd_strdup(name
);
1878 h
->pinentry_timeout
= -30;
1879 h
->pinentry_tries
= 3;
1881 h
->prot
= PWMD_IP_ANY
;
1884 if (ttyname(STDOUT_FILENO
)) {
1887 ttyname_r(STDOUT_FILENO
, buf
, sizeof(buf
));
1888 h
->pinentry_tty
= pwmd_strdup(buf
);
1890 if (!h
->pinentry_tty
)
1894 if (getenv("TERM") && h
->pinentry_tty
) {
1895 h
->pinentry_term
= pwmd_strdup(getenv("TERM"));
1897 if (!h
->pinentry_term
)
1901 if (getenv("DISPLAY")) {
1902 h
->pinentry_display
= pwmd_strdup(getenv("DISPLAY"));
1904 if (!h
->pinentry_display
)
1915 void pwmd_free(void *ptr
)
1920 void *pwmd_malloc(size_t size
)
1922 return _xmalloc(size
);
1925 void *pwmd_calloc(size_t nmemb
, size_t size
)
1927 return _xcalloc(nmemb
, size
);
1930 void *pwmd_realloc(void *ptr
, size_t size
)
1932 return _xrealloc(ptr
, size
);
1935 char *pwmd_strdup(const char *str
)
1937 return _xstrdup(str
);
1940 char *pwmd_strdup_printf(const char *fmt
, ...)
1951 len
= vsnprintf(NULL
, 0, fmt
, ap
);
1953 buf
= pwmd_malloc(++len
);
1956 vsnprintf(buf
, len
, fmt
, ap2
);
1962 gpg_error_t
pwmd_getpin(pwm_t
*pwm
, const char *filename
, char **result
,
1963 pwmd_pinentry_t which
)
1965 #ifndef WITH_PINENTRY
1966 return GPG_ERR_NOT_IMPLEMENTED
;
1968 return _pwmd_getpin(pwm
, filename
, result
, which
);