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
)) {
72 return N_("No file is open");
74 return N_("General LibXML error");
76 return N_("File modified");
78 return N_("Unknown error");
85 const char *pwmd_strerror(gpg_error_t code
)
87 const char *p
= _pwmd_strerror(code
);
89 return p
? p
: gpg_strerror(code
);
92 int pwmd_strerror_r(gpg_error_t code
, char *buf
, size_t size
)
94 const char *p
= _pwmd_strerror(code
);
97 snprintf(buf
, size
, "%s", p
);
105 return gpg_strerror_r(code
, buf
, size
);
108 gpg_error_t
pwmd_init()
110 static int initialized
;
119 bindtextdomain("libpwmd", LOCALEDIR
);
125 assuan_set_malloc_hooks(pwmd_malloc
, pwmd_realloc
, pwmd_free
);
126 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT
);
131 gpg_error_t
_connect_finalize(pwm_t
*pwm
)
134 int n
= assuan_get_active_fds(pwm
->ctx
, 0, active
, N_ARRAY(active
));
138 return GPG_ERR_EBADFD
;
144 assuan_set_pointer(pwm
->ctx
, pwm
);
147 // Until X11 forwarding is supported, disable the remote pwmd pinentry.
149 pwm
->tcp_conn
->state
= SSH_NONE
;
150 rc
= pwmd_command(pwm
, NULL
, "SET ENABLE_PINENTRY=0");
158 rc
= pwmd_command(pwm
, NULL
, "SET NAME=%s", pwm
->name
);
167 static gpg_error_t
_pwmd_connect_url(pwm_t
*pwm
, const char *url
, int async
)
169 char *p
= (char *)url
;
173 return GPG_ERR_INV_ARG
;
175 if (!p
|| !strncmp(p
, "file://", 7) || !strncmp(p
, "local://", 8)) {
177 if (!strncmp(p
, "file://", 7))
185 else if (!strncmp(p
, "ssh://", 6) || !strncmp(p
, "ssh6://", 7) ||
186 !strncmp(p
, "ssh4://", 7)) {
188 return GPG_ERR_NOT_IMPLEMENTED
;
192 char *identity
= NULL
;
193 char *known_hosts
= NULL
;
194 char *username
= NULL
;
196 if (!strncmp(p
, "ssh6://", 7)) {
197 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV6
);
200 else if (!strncmp(p
, "ssh4://", 7)) {
201 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV4
);
205 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IP_ANY
);
212 rc
= _parse_ssh_url(p
, &host
, &port
, &username
, &identity
,
219 rc
= pwmd_ssh_connect_async(pwm
, host
, port
, identity
, username
,
222 rc
= pwmd_ssh_connect(pwm
, host
, port
, identity
, username
,
236 pwmd_free(known_hosts
);
243 rc
= pwmd_connect(pwm
, p
);
244 pwm
->state
= ASYNC_DONE
;
248 gpg_error_t
pwmd_connect_url(pwm_t
*pwm
, const char *url
)
250 return _pwmd_connect_url(pwm
, url
, 0);
253 gpg_error_t
pwmd_connect_url_async(pwm_t
*pwm
, const char *url
)
255 return _pwmd_connect_url(pwm
, url
, 1);
258 gpg_error_t
pwmd_connect(pwm_t
*pwm
, const char *path
)
260 char *socketpath
= NULL
;
261 assuan_context_t ctx
;
267 return GPG_ERR_INV_ARG
;
269 pwbuf
= _getpwuid(&pw
);
272 return gpg_error_from_errno(errno
);
275 socketpath
= pwmd_strdup_printf("%s/.pwmd/socket", pw
.pw_dir
);
277 socketpath
= _expand_homedir((char *)path
, &pw
);
282 return gpg_error_from_errno(ENOMEM
);
284 rc
= assuan_socket_connect_ext(&ctx
, socketpath
, -1, 0);
285 pwmd_free(socketpath
);
288 return gpg_err_code(rc
);
291 return _connect_finalize(pwm
);
294 static void disconnect(pwm_t
*pwm
)
296 if (!pwm
|| !pwm
->ctx
)
299 assuan_disconnect(pwm
->ctx
);
304 void pwmd_close(pwm_t
*pwm
)
312 pwmd_free(pwm
->password
);
315 pwmd_free(pwm
->title
);
318 pwmd_free(pwm
->desc
);
321 pwmd_free(pwm
->prompt
);
323 if (pwm
->pinentry_tty
)
324 pwmd_free(pwm
->pinentry_tty
);
326 if (pwm
->pinentry_display
)
327 pwmd_free(pwm
->pinentry_display
);
329 if (pwm
->pinentry_term
)
330 pwmd_free(pwm
->pinentry_term
);
333 pwmd_free(pwm
->lcctype
);
336 pwmd_free(pwm
->lcmessages
);
339 pwmd_free(pwm
->filename
);
342 pwmd_free(pwm
->name
);
346 _free_ssh_conn(pwm
->tcp_conn
);
351 _pinentry_disconnect(pwm
);
357 static gpg_error_t
do_async_command(pwm_t
*pwm
, char **result
)
363 s
= pwmd_process(pwm
, &rc
, result
);
365 if (s
!= ASYNC_DONE
) {
372 } while (s
!= ASYNC_DONE
);
377 gpg_error_t
pwmd_ssh_connect_async(pwm_t
*pwm
, const char *host
, int port
,
378 const char *identity
, const char *user
, const char *known_hosts
)
381 return GPG_ERR_NOT_IMPLEMENTED
;
383 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, identity
, user
,
384 known_hosts
, ASYNC_CMD_CONNECT
);
388 gpg_error_t
pwmd_ssh_connect(pwm_t
*pwm
, const char *host
, int port
,
389 const char *identity
, const char *user
, const char *known_hosts
)
392 return GPG_ERR_NOT_IMPLEMENTED
;
396 rc
= _do_pwmd_ssh_connect_async(pwm
, host
, port
, identity
, user
,
397 known_hosts
, ASYNC_CMD_CONNECT
);
398 return rc
|| do_async_command(pwm
, NULL
);
402 gpg_error_t
pwmd_get_hostkey(pwm_t
*pwm
, const char *host
, int port
,
406 return GPG_ERR_NOT_IMPLEMENTED
;
410 rc
= _do_pwmd_ssh_connect_async(pwm
, host
, port
, NULL
, NULL
, NULL
,
413 return rc
|| do_async_command(pwm
, result
);
417 gpg_error_t
pwmd_get_hostkey_async(pwm_t
*pwm
, const char *host
, int port
)
420 return GPG_ERR_NOT_IMPLEMENTED
;
422 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, NULL
, NULL
, NULL
,
427 static int inquire_realloc_cb(void *data
, const void *buffer
, size_t len
)
429 membuf_t
*mem
= (membuf_t
*)data
;
435 if ((p
= pwmd_realloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
436 return gpg_error_from_errno(ENOMEM
);
439 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
444 static int inquire_cb(void *data
, const char *keyword
)
446 pwm_t
*pwm
= (pwm_t
*)data
;
450 /* Shouldn't get this far without a callback. */
451 if (!pwm
->inquire_func
)
452 return GPG_ERR_INV_ARG
;
459 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
, &result
, &len
);
460 rc
= gpg_err_code(rc
);
462 if (rc
== GPG_ERR_EOF
|| !rc
) {
463 if (len
<= 0 && !result
) {
467 else if ((len
<= 0 && result
) || (len
&& !result
)) {
468 rc
= GPG_ERR_INV_ARG
;
474 arc
= assuan_send_data(pwm
->ctx
, result
, len
);
475 arc
= gpg_err_code(arc
);
477 if (rc
== GPG_ERR_EOF
) {
484 if (rc
== GPG_ERR_EAGAIN
) {
494 pwm
->inquire_sent
+= len
;
496 if (pwm
->status_func
) {
497 char buf
[ASSUAN_LINELENGTH
];
499 snprintf(buf
, sizeof(buf
), "XFER %u %u", pwm
->inquire_sent
,
501 rc
= pwm
->status_func(pwm
->status_data
, buf
);
508 rc
= _pwmd_process(pwm
);
510 if (rc
== GPG_ERR_EAGAIN
)
514 if (!rc
&& is_eagain
)
518 return gpg_err_code(rc
);
521 static gpg_error_t
do_nb_command(pwm_t
*pwm
, const char *cmd
, ...)
528 if (pwm
->state
== ASYNC_DONE
)
529 pwm
->state
= ASYNC_INIT
;
531 if (pwm
->state
!= ASYNC_INIT
)
532 return GPG_ERR_INV_STATE
;
534 buf
= pwmd_malloc(ASSUAN_LINELENGTH
+1);
537 return gpg_error_from_errno(ENOMEM
);
540 len
= vsnprintf(buf
, ASSUAN_LINELENGTH
+1, cmd
, ap
);
543 if (len
>= ASSUAN_LINELENGTH
+1) {
545 return GPG_ERR_LINE_TOO_LONG
;
548 rc
= assuan_write_line(pwm
->ctx
, buf
);
552 pwm
->state
= ASYNC_PROCESS
;
554 return gpg_err_code(rc
);
557 gpg_error_t
pwmd_open_async(pwm_t
*pwm
, const char *filename
)
560 const char *f
= NULL
;
563 if (!pwm
|| !filename
)
564 return GPG_ERR_INV_ARG
;
567 return GPG_ERR_INV_STATE
;
569 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
570 return GPG_ERR_ASS_NESTED_COMMANDS
;
572 if (pwm
->lastcmd
== ASYNC_CMD_NONE
) {
576 pwmd_free(pwm
->filename
);
578 pwm
->filename
= pwmd_strdup(filename
);
581 return gpg_error_from_errno(ENOMEM
);
583 gpg_error_t rc
= send_pinentry_options(pwm
);
588 rc
= get_custom_passphrase(pwm
, &p
);
590 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
596 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN2
) {
601 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN
) {
602 rc
= set_pinentry_retry(pwm
);
611 return GPG_ERR_INV_STATE
;
613 pwm
->cmd
= ASYNC_CMD_OPEN
;
614 return do_nb_command(pwm
, "OPEN %s %s", f
, p
? p
: "");
617 gpg_error_t
pwmd_save_async(pwm_t
*pwm
)
622 return GPG_ERR_INV_ARG
;
625 return GPG_ERR_INV_STATE
;
627 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
628 return GPG_ERR_ASS_NESTED_COMMANDS
;
630 if (pwm
->lastcmd
!= ASYNC_CMD_SAVE2
) {
631 gpg_error_t rc
= send_pinentry_options(pwm
);
636 rc
= get_custom_passphrase(pwm
, &p
);
638 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
646 pwm
->cmd
= ASYNC_CMD_SAVE
;
647 return do_nb_command(pwm
, "SAVE %s", p
? p
: "");
650 static gpg_error_t
parse_assuan_line(pwm_t
*pwm
)
656 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
659 if (line
[0] == 'O' && line
[1] == 'K' &&
660 (line
[2] == 0 || line
[2] == ' ')) {
661 pwm
->state
= ASYNC_DONE
;
663 else if (line
[0] == '#') {
665 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' ')) {
666 if (pwm
->status_func
) {
667 rc
= pwm
->status_func(pwm
->status_data
,
668 line
[1] == 0 ? line
+1 : line
+2);
671 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
672 (line
[3] == 0 || line
[3] == ' ')) {
675 pwm
->state
= ASYNC_DONE
;
679 return gpg_err_code(rc
);
682 gpg_error_t
pwmd_pending_line(pwm_t
*pwm
)
685 return GPG_ERR_INV_ARG
;
688 return GPG_ERR_INV_STATE
;
690 return assuan_pending_line(pwm
->ctx
) ? 0 : GPG_ERR_NO_DATA
;
693 static pwmd_async_t
reset_async(pwm_t
*pwm
, int done
)
695 pwm
->state
= ASYNC_INIT
;
696 pwm
->cmd
= pwm
->lastcmd
= ASYNC_CMD_NONE
;
699 if (pwm
->nb_fd
!= -1) {
704 if (pwm
->_password
) {
705 pwmd_free(pwm
->_password
);
706 pwm
->_password
= NULL
;
711 pwm
->tcp_conn
->rc
= 0;
713 if (done
&& pwm
->tcp_conn
) {
714 _free_ssh_conn(pwm
->tcp_conn
);
715 pwm
->tcp_conn
= NULL
;
723 * Used for processing status messages when not in an async command and for
724 * waiting for the result from pwmd_open_async() and pwmd_save_async().
726 static gpg_error_t
_pwmd_process(pwm_t
*pwm
)
730 struct timeval tv
= {0, 0};
734 FD_SET(pwm
->fd
, &fds
);
736 n
= pth_select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
738 n
= select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
742 return gpg_error_from_syserror();
745 if (FD_ISSET(pwm
->fd
, &fds
))
746 rc
= parse_assuan_line(pwm
);
749 while (!rc
&& assuan_pending_line(pwm
->ctx
))
750 rc
= parse_assuan_line(pwm
);
752 return gpg_err_code(rc
);
755 static void reset_handle(pwm_t
*h
)
760 _pinentry_disconnect(h
);
768 gpg_error_t
pwmd_disconnect(pwm_t
*pwm
)
771 return GPG_ERR_INV_ARG
;
774 if (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1)
778 return GPG_ERR_INV_STATE
;
784 _ssh_disconnect(pwm
);
791 pwmd_async_t
pwmd_process(pwm_t
*pwm
, gpg_error_t
*rc
, char **result
)
793 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
796 struct timeval tv
= {0, 0};
803 return GPG_ERR_INV_ARG
;
808 *rc
= GPG_ERR_INV_ARG
;
811 else if (!pwm
->ctx
) {
814 *rc
= GPG_ERR_INV_STATE
;
818 case ASYNC_CMD_CONNECT
:
819 case ASYNC_CMD_HOSTKEY
:
825 /* When not in a command, this will let libassuan process status messages
826 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
827 * descriptor returned by pwmd_get_fd() to determine when this should be
828 * called or call pwmd_pending_line() to determine whether a buffered line
829 * needs to be processed. */
830 if (pwm
->cmd
== ASYNC_CMD_NONE
) {
831 *rc
= _pwmd_process(pwm
);
835 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
836 if (pwm
->state
== ASYNC_DONE
) {
837 *rc
= _pwmd_process(pwm
);
838 return reset_async(pwm
, 0);
841 if (pwm
->state
!= ASYNC_PROCESS
) {
842 *rc
= GPG_ERR_INV_STATE
;
847 if (pwm
->cmd
== ASYNC_CMD_DNS
) {
850 if (pwm
->tcp_conn
->rc
) {
851 *rc
= pwm
->tcp_conn
->rc
;
852 return reset_async(pwm
, 1);
857 n
= ares_fds(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
859 /* Shouldn't happen. */
864 n
= pth_select(n
, &rfds
, &wfds
, NULL
, &tv
);
866 n
= select(n
, &rfds
, &wfds
, NULL
, &tv
);
870 *rc
= gpg_error_from_syserror();
871 return reset_async(pwm
, 1);
875 ares_process(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
879 else if (pwm
->cmd
== ASYNC_CMD_CONNECT
) {
880 if (pwm
->tcp_conn
->rc
== GPG_ERR_EINPROGRESS
) {
882 socklen_t len
= sizeof(int);
885 FD_SET(pwm
->tcp_conn
->fd
, &fds
);
887 n
= pth_select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
889 n
= select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
892 if (!n
|| !FD_ISSET(pwm
->tcp_conn
->fd
, &fds
))
895 *rc
= gpg_error_from_syserror();
896 return reset_async(pwm
, 1);
899 ret
= getsockopt(pwm
->tcp_conn
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
902 *rc
= ret
? gpg_error_from_syserror() : gpg_error_from_errno(n
);
903 return reset_async(pwm
, 1);
906 pwm
->tcp_conn
->state
= SSH_NONE
;
907 pwm
->tcp_conn
->rc
= 0;
908 *rc
= _setup_ssh_session(pwm
);
910 if (*rc
&& *rc
!= GPG_ERR_EAGAIN
)
911 return reset_async(pwm
, 1);
913 else if (pwm
->tcp_conn
->rc
) {
914 *rc
= pwm
->tcp_conn
->rc
;
915 return reset_async(pwm
, 1);
918 switch (pwm
->tcp_conn
->state
) {
920 *rc
= _setup_ssh_init(pwm
);
923 *rc
= _setup_ssh_authlist(pwm
);
926 *rc
= _setup_ssh_auth(pwm
);
929 *rc
= _setup_ssh_channel(pwm
);
932 *rc
= _setup_ssh_shell(pwm
);
938 if (*rc
== GPG_ERR_EAGAIN
) {
940 return ASYNC_PROCESS
;
944 switch (pwm
->tcp_conn
->cmd
) {
945 case ASYNC_CMD_HOSTKEY
:
946 *result
= pwmd_strdup(pwm
->tcp_conn
->hostkey
);
949 *rc
= GPG_ERR_ENOMEM
;
956 return reset_async(pwm
, *rc
? 1 : 0);
961 if (pwm
->cmd
== ASYNC_CMD_OPEN2
|| pwm
->cmd
== ASYNC_CMD_SAVE2
) {
964 if (pwm
->nb_fd
== -1) {
965 *rc
= GPG_ERR_INV_STATE
;
966 return reset_async(pwm
, 0);
970 FD_SET(pwm
->nb_fd
, &fds
);
971 FD_SET(pwm
->fd
, &fds
);
973 n
= pth_select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
975 n
= select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
978 *rc
= gpg_error_from_syserror();
979 return reset_async(pwm
, 0);
982 if (n
> 0 && FD_ISSET(pwm
->nb_fd
, &fds
)) {
985 size_t len
= pth_read(pwm
->nb_fd
, &nb
, sizeof(nb
));
987 size_t len
= read(pwm
->nb_fd
, &nb
, sizeof(nb
));
989 waitpid(pwm
->nb_pid
, &status
, WNOHANG
);
991 if (len
!= sizeof(nb
)) {
992 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
993 *rc
= gpg_error_from_syserror();
994 return reset_async(pwm
, 0);
1000 return reset_async(pwm
, 0);
1002 /* Since the non-blocking pinentry returned a success, do a
1003 * non-blocking OPEN or SAVE. */
1004 pwmd_async_cmd_t c
= pwm
->cmd
;
1005 reset_async(pwm
, 0);
1006 pwm
->_password
= pwmd_strdup(nb
.password
);
1007 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
1010 if (!pwm
->_password
) {
1011 *rc
= gpg_error_from_errno(ENOMEM
);
1012 return reset_async(pwm
, 0);
1015 if (c
== ASYNC_CMD_SAVE2
)
1016 *rc
= pwmd_save_async(pwm
);
1018 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
1021 reset_async(pwm
, 0);
1025 return ASYNC_PROCESS
;
1028 /* Fall through so status messages can be processed during the
1034 *rc
= GPG_ERR_INV_STATE
;
1035 return reset_async(pwm
, 0);
1038 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
1040 *rc
= _pwmd_process(pwm
);
1042 if (*rc
&& *rc
!= GPG_ERR_INV_PASSPHRASE
)
1043 return reset_async(pwm
, 0);
1045 if (pwm
->cmd
== ASYNC_CMD_OPEN
&&
1046 *rc
== GPG_ERR_INV_PASSPHRASE
&&
1048 (!pwm
->tcp_conn
|| (pwm
->tcp_conn
&& pwm
->lastcmd
== ASYNC_CMD_OPEN2
)) &&
1050 ++pwm
->pin_try
< pwm
->pinentry_tries
) {
1051 if (!get_custom_passphrase(pwm
, NULL
))
1054 #ifdef WITH_PINENTRY
1055 if (pwm
->_password
) {
1056 reset_async(pwm
, 0);
1057 pwm
->lastcmd
= ASYNC_CMD_OPEN2
;
1058 *rc
= pwmd_open_async2(pwm
, pwm
->filename
);
1062 reset_async(pwm
, 0);
1063 pwm
->lastcmd
= ASYNC_CMD_OPEN
;
1064 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
1065 #ifdef WITH_PINENTRY
1071 if (*rc
|| pwm
->state
== ASYNC_DONE
)
1072 return reset_async(pwm
, 0);
1077 gpg_error_t
_assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
1078 char **result
, const char *cmd
)
1084 return GPG_ERR_INV_ARG
;
1086 if (strlen(cmd
) >= ASSUAN_LINELENGTH
+1)
1087 return GPG_ERR_LINE_TOO_LONG
;
1091 rc
= assuan_transact(ctx
, cmd
, inquire_realloc_cb
, &data
,
1093 pwm
->pctx
== ctx
? pwm
->_inquire_func
: inquire_cb
,
1094 pwm
->pctx
== ctx
? pwm
->_inquire_data
: pwm
,
1098 pwm
->status_func
, pwm
->status_data
);
1102 pwmd_free(data
.buf
);
1108 inquire_realloc_cb(&data
, "", 1);
1111 pwmd_free(data
.buf
);
1112 rc
= GPG_ERR_INV_ARG
;
1115 *result
= (char *)data
.buf
;
1119 return gpg_err_code(rc
);
1122 gpg_error_t
pwmd_inquire(pwm_t
*pwm
, const char *cmd
, pwmd_inquire_cb_t fn
,
1125 if (!pwm
|| !cmd
|| !fn
)
1126 return GPG_ERR_INV_ARG
;
1129 return GPG_ERR_INV_STATE
;
1131 pwm
->inquire_func
= fn
;
1132 pwm
->inquire_data
= data
;
1133 pwm
->inquire_sent
= 0;
1134 return _assuan_command(pwm
, pwm
->ctx
, NULL
, cmd
);
1137 gpg_error_t
pwmd_command_ap(pwm_t
*pwm
, char **result
, const char *cmd
,
1145 return GPG_ERR_INV_ARG
;
1148 return GPG_ERR_INV_STATE
;
1151 * C99 allows the dst pointer to be null which will calculate the length
1152 * of the would-be result and return it.
1155 len
= vsnprintf(NULL
, 0, cmd
, ap
)+1;
1156 buf
= (char *)pwmd_malloc(len
);
1160 return gpg_error_from_errno(ENOMEM
);
1163 len
= vsnprintf(buf
, len
, cmd
, ap2
);
1166 if (buf
[strlen(buf
)-1] == '\n')
1167 buf
[strlen(buf
)-1] = 0;
1169 if (buf
[strlen(buf
)-1] == '\r')
1170 buf
[strlen(buf
)-1] = 0;
1172 gpg_error_t rc
= _assuan_command(pwm
, pwm
->ctx
, result
, buf
);
1177 gpg_error_t
pwmd_command(pwm_t
*pwm
, char **result
, const char *cmd
, ...)
1182 return GPG_ERR_INV_ARG
;
1185 return GPG_ERR_INV_STATE
;
1191 gpg_error_t rc
= pwmd_command_ap(pwm
, result
, cmd
, ap
);
1196 static gpg_error_t
send_pinentry_options(pwm_t
*pwm
)
1200 if (pwm
->pinentry_path
) {
1201 rc
= pwmd_command(pwm
, NULL
, "SET PINENTRY_PATH=%s",
1202 pwm
->pinentry_path
);
1208 if (pwm
->pinentry_tty
) {
1209 rc
= pwmd_command(pwm
, NULL
, "SET TTYNAME=%s", pwm
->pinentry_tty
);
1215 if (pwm
->pinentry_term
) {
1216 rc
= pwmd_command(pwm
, NULL
, "SET TTYTYPE=%s", pwm
->pinentry_term
);
1222 if (pwm
->pinentry_display
) {
1223 rc
= pwmd_command(pwm
, NULL
, "SET DISPLAY=%s",
1224 pwm
->pinentry_display
);
1231 rc
= pwmd_command(pwm
, NULL
, "SET TITLE=%s", pwm
->title
);
1238 rc
= pwmd_command(pwm
, NULL
, "SET DESC=%s", pwm
->desc
);
1245 rc
= pwmd_command(pwm
, NULL
, "SET PROMPT=%s", pwm
->prompt
);
1252 rc
= pwmd_command(pwm
, NULL
, "SET LC_CTYPE=%s", pwm
->lcctype
);
1258 if (pwm
->lcmessages
) {
1259 rc
= pwmd_command(pwm
, NULL
, "SET LC_MESSAGES=%s", pwm
->lcmessages
);
1265 if (pwm
->pinentry_timeout
>= 0 && !pwm
->pin_try
) {
1266 rc
= pwmd_command(pwm
, NULL
, "SET PINENTRY_TIMEOUT=%i",
1267 pwm
->pinentry_timeout
);
1276 gpg_error_t
pwmd_socket_type(pwm_t
*pwm
, pwmd_socket_t
*result
)
1278 if (!pwm
|| !result
)
1279 return GPG_ERR_INV_ARG
;
1282 if ((pwm
->fd
== -1 && !pwm
->tcp_conn
) ||
1283 (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1))
1287 return GPG_ERR_INV_STATE
;
1290 *result
= pwm
->tcp_conn
? PWMD_SOCKET_SSH
: PWMD_SOCKET_LOCAL
;
1292 *result
= PWMD_SOCKET_LOCAL
;
1297 static gpg_error_t
set_pinentry_retry(pwm_t
*pwm
)
1301 if (pwm
->pin_try
== 1) {
1302 rc
= pwmd_command(pwm
, NULL
, "SET TITLE=%s",
1303 N_("Invalid passphrase, please try again."));
1308 rc
= pwmd_command(pwm
, NULL
, "SET PINENTRY_TIMEOUT=0");
1314 static gpg_error_t
get_custom_passphrase(pwm_t
*pwm
, char **result
)
1316 gpg_error_t rc
= GPG_ERR_NO_DATA
;
1321 if (pwm
->password
|| pwm
->passfunc
)
1325 if (pwm
->password
) {
1327 *result
= pwm
->password
;
1329 else if (pwm
->passfunc
)
1330 rc
= pwm
->passfunc(pwm
->passdata
, result
);
1335 static gpg_error_t
do_pwmd_open(pwm_t
*pwm
, const char *filename
, int nb
,
1338 char *result
= NULL
;
1339 char *password
= NULL
;
1342 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1345 if (!pwm
|| !filename
|| !*filename
)
1346 return GPG_ERR_INV_ARG
;
1349 return GPG_ERR_INV_STATE
;
1352 * Avoid calling pinentry if the password is cached on the server or if
1353 * this is a new file.
1355 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", filename
);
1357 if (rc
== GPG_ERR_ENOENT
)
1360 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1363 if (rc
== GPG_ERR_NOT_FOUND
) {
1364 rc
= get_custom_passphrase(pwm
, &password
);
1366 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
1368 else if (rc
== GPG_ERR_NO_DATA
)
1369 rc
= GPG_ERR_NOT_FOUND
;
1374 #ifdef WITH_PINENTRY
1375 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1376 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1377 if (!pwm
->pin_try
) {
1378 rc
= pwmd_command(pwm
, NULL
, "SET ENABLE_PINENTRY=0");
1384 rc
= _pinentry_open(pwm
, filename
, &password
, nb
);
1386 /* pwmd_process() should be called if using a non-blocking local
1388 if (rc
|| (!rc
&& nb
))
1394 reset_async(pwm
, 0);
1397 if (!local_pinentry
&& !pwm
->tcp_conn
&& !pwm
->pin_try
) {
1399 if (!local_pinentry
&& !pwm
->pin_try
) {
1401 rc
= send_pinentry_options(pwm
);
1407 rc
= pwmd_command(pwm
, NULL
, "OPEN %s %s", filename
,
1408 password
? password
: "");
1411 * Keep the user defined password set with pwmd_setopt(). The password may
1412 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1414 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1415 pwmd_free(password
);
1417 if (rc
== GPG_ERR_INV_PASSPHRASE
) {
1418 if (++pwm
->pin_try
< pwm
->pinentry_tries
) {
1419 if (!get_custom_passphrase(pwm
, NULL
))
1422 #ifdef WITH_PINENTRY
1424 if (pwm
->tcp_conn
&& !local_pinentry
)
1426 else if (local_pinentry
)
1427 rc
= _getpin(pwm
, &password
, PWMD_PINENTRY_OPEN_FAILED
);
1431 rc
= _getpin(pwm
, &password
, PWMD_PINENTRY_OPEN_FAILED
);
1441 rc
= set_pinentry_retry(pwm
);
1448 #ifdef WITH_PINENTRY
1449 else if (local_pinentry
)
1450 _pinentry_disconnect(pwm
);
1456 #ifdef WITH_PINENTRY
1457 else if (rc
&& local_pinentry
)
1458 _pinentry_disconnect(pwm
);
1463 pwmd_free(pwm
->filename
);
1465 pwm
->filename
= pwmd_strdup(filename
);
1471 gpg_error_t
pwmd_open2(pwm_t
*pwm
, const char *filename
)
1473 #ifndef WITH_PINENTRY
1474 return GPG_ERR_NOT_IMPLEMENTED
;
1476 return do_pwmd_open(pwm
, filename
, 0, 1);
1480 gpg_error_t
pwmd_open(pwm_t
*pwm
, const char *filename
)
1482 return do_pwmd_open(pwm
, filename
, 0, 0);
1485 gpg_error_t
pwmd_open_async2(pwm_t
*pwm
, const char *filename
)
1487 #ifndef WITH_PINENTRY
1488 return GPG_ERR_NOT_IMPLEMENTED
;
1490 if (!pwm
|| !filename
)
1491 return GPG_ERR_INV_ARG
;
1494 return GPG_ERR_INV_STATE
;
1496 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1497 return GPG_ERR_ASS_NESTED_COMMANDS
;
1499 /* Initialize a new command since this is not a pinentry retry. */
1500 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1503 pwm
->cmd
= ASYNC_CMD_OPEN2
;
1504 pwm
->state
= ASYNC_PROCESS
;
1505 gpg_error_t rc
= do_pwmd_open(pwm
, filename
, 1, 1);
1508 reset_async(pwm
, 0);
1514 static gpg_error_t
do_pwmd_save(pwm_t
*pwm
, int nb
, int local_pinentry
)
1516 char *result
= NULL
;
1517 char *password
= NULL
;
1521 return GPG_ERR_INV_ARG
;
1524 return GPG_ERR_INV_STATE
;
1526 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", pwm
->filename
);
1528 if (rc
== GPG_ERR_ENOENT
)
1529 rc
= GPG_ERR_NOT_FOUND
;
1531 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1534 if (rc
== GPG_ERR_NOT_FOUND
) {
1535 rc
= get_custom_passphrase(pwm
, &password
);
1537 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
1539 else if (rc
== GPG_ERR_NO_DATA
)
1540 rc
= GPG_ERR_NOT_FOUND
;
1545 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1546 #ifdef WITH_PINENTRY
1547 /* Get the password using the LOCAL pinentry. */
1551 pwmd_nb_status_t pw
;
1554 return gpg_error_from_syserror();
1567 pw
.error
= _do_save_getpin(pwm
, &password
);
1570 snprintf(pw
.password
, sizeof(pw
.password
), "%s",
1572 pwmd_free(password
);
1575 pth_write(p
[1], &pw
, sizeof(pw
));
1577 write(p
[1], &pw
, sizeof(pw
));
1579 memset(&pw
, 0, sizeof(pw
));
1584 rc
= gpg_error_from_syserror();
1598 rc
= _do_save_getpin(pwm
, &password
);
1605 pwm
->state
= ASYNC_DONE
;
1608 reset_async(pwm
, 0);
1611 if (!local_pinentry
&& !pwm
->tcp_conn
) {
1613 if (!local_pinentry
) {
1615 rc
= send_pinentry_options(pwm
);
1621 rc
= pwmd_command(pwm
, NULL
, "SAVE %s", password
? password
: "");
1623 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1624 pwmd_free(password
);
1629 gpg_error_t
pwmd_save_async2(pwm_t
*pwm
)
1631 #ifndef WITH_PINENTRY
1632 return GPG_ERR_NOT_IMPLEMENTED
;
1635 return GPG_ERR_INV_ARG
;
1638 return GPG_ERR_INV_STATE
;
1640 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1641 return GPG_ERR_ASS_NESTED_COMMANDS
;
1643 pwm
->cmd
= ASYNC_CMD_SAVE2
;
1644 pwm
->state
= ASYNC_PROCESS
;
1645 gpg_error_t rc
= do_pwmd_save(pwm
, 1, 1);
1648 reset_async(pwm
, 0);
1654 gpg_error_t
pwmd_save2(pwm_t
*pwm
)
1656 #ifndef WITH_PINENTRY
1657 return GPG_ERR_NOT_IMPLEMENTED
;
1659 return do_pwmd_save(pwm
, 0, 1);
1663 gpg_error_t
pwmd_save(pwm_t
*pwm
)
1665 return do_pwmd_save(pwm
, 0, 0);
1668 gpg_error_t
pwmd_setopt(pwm_t
*pwm
, pwmd_option_t opt
, ...)
1671 int n
= va_arg(ap
, int);
1676 return GPG_ERR_INV_ARG
;
1681 case PWMD_OPTION_INQUIRE_TOTAL
:
1682 n
= va_arg(ap
, size_t);
1683 pwm
->inquire_total
= n
;
1685 case PWMD_OPTION_STATUS_CB
:
1686 pwm
->status_func
= va_arg(ap
, pwmd_status_cb_t
);
1688 case PWMD_OPTION_STATUS_DATA
:
1689 pwm
->status_data
= va_arg(ap
, void *);
1691 case PWMD_OPTION_PASSPHRASE_CB
:
1692 pwm
->passfunc
= va_arg(ap
, pwmd_passphrase_cb_t
);
1694 case PWMD_OPTION_PASSPHRASE_DATA
:
1695 pwm
->passdata
= va_arg(ap
, void *);
1697 case PWMD_OPTION_PASSPHRASE
:
1698 arg1
= va_arg(ap
, char *);
1701 pwmd_free(pwm
->password
);
1703 pwm
->password
= arg1
? pwmd_strdup(arg1
) : NULL
;
1705 case PWMD_OPTION_PINENTRY_TRIES
:
1706 n
= va_arg(ap
, int);
1710 rc
= GPG_ERR_INV_VALUE
;
1713 pwm
->pinentry_tries
= n
;
1715 case PWMD_OPTION_PINENTRY_TIMEOUT
:
1716 n
= va_arg(ap
, int);
1720 rc
= GPG_ERR_INV_VALUE
;
1723 pwm
->pinentry_timeout
= n
;
1725 case PWMD_OPTION_PINENTRY_PATH
:
1726 if (pwm
->pinentry_path
)
1727 pwmd_free(pwm
->pinentry_path
);
1729 pwm
->pinentry_path
= _expand_homedir(va_arg(ap
, char *), NULL
);
1731 case PWMD_OPTION_PINENTRY_TTY
:
1732 arg1
= va_arg(ap
, char *);
1734 if (pwm
->pinentry_tty
)
1735 pwmd_free(pwm
->pinentry_tty
);
1737 pwm
->pinentry_tty
= arg1
? pwmd_strdup(arg1
) : NULL
;
1739 case PWMD_OPTION_PINENTRY_DISPLAY
:
1740 if (pwm
->pinentry_display
)
1741 pwmd_free(pwm
->pinentry_display
);
1743 pwm
->pinentry_display
= pwmd_strdup(va_arg(ap
, char *));
1745 case PWMD_OPTION_PINENTRY_TERM
:
1746 arg1
= va_arg(ap
, char *);
1748 if (pwm
->pinentry_term
)
1749 pwmd_free(pwm
->pinentry_term
);
1751 pwm
->pinentry_term
= arg1
? pwmd_strdup(arg1
) : NULL
;
1753 case PWMD_OPTION_PINENTRY_TITLE
:
1755 pwmd_free(pwm
->title
);
1757 pwm
->title
= _percent_escape(va_arg(ap
, char *));
1759 case PWMD_OPTION_PINENTRY_PROMPT
:
1761 pwmd_free(pwm
->prompt
);
1763 pwm
->prompt
= _percent_escape(va_arg(ap
, char *));
1765 case PWMD_OPTION_PINENTRY_DESC
:
1767 pwmd_free(pwm
->desc
);
1769 pwm
->desc
= _percent_escape(va_arg(ap
, char *));
1771 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
1772 arg1
= va_arg(ap
, char *);
1775 pwmd_free(pwm
->lcctype
);
1777 pwm
->lcctype
= arg1
? pwmd_strdup(arg1
) : NULL
;
1779 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
1780 arg1
= va_arg(ap
, char *);
1782 if (pwm
->lcmessages
)
1783 pwmd_free(pwm
->lcmessages
);
1785 pwm
->lcmessages
= arg1
? pwmd_strdup(arg1
) : NULL
;
1787 case PWMD_OPTION_IP_VERSION
:
1789 n
= va_arg(ap
, int);
1798 rc
= GPG_ERR_INV_VALUE
;
1804 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1807 case PWMD_OPTION_KNOWNHOST_CB
:
1809 pwm
->kh_cb
= va_arg(ap
, pwmd_knownhost_cb_t
);
1811 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1814 case PWMD_OPTION_KNOWNHOST_DATA
:
1816 pwm
->kh_data
= va_arg(ap
, void *);
1818 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1822 rc
= GPG_ERR_UNKNOWN_OPTION
;
1830 gpg_error_t
pwmd_get_fds(pwm_t
*pwm
, pwmd_fd_t
*fds
, int *n_fds
)
1835 int afds
[ARES_GETSOCK_MAXNUM
];
1840 if (!pwm
|| !fds
|| !n_fds
|| *n_fds
<= 0)
1841 return GPG_ERR_INV_ARG
;
1845 memset(afds
, 0, sizeof(int)*ARES_GETSOCK_MAXNUM
);
1847 memset(fds
, 0, sizeof(pwmd_fd_t
)*in_total
);
1852 case ASYNC_CMD_NONE
:
1853 case ASYNC_CMD_OPEN
:
1854 case ASYNC_CMD_SAVE
:
1855 #ifdef WITH_PINENTRY
1859 return GPG_ERR_INV_STATE
;
1862 fds
[fd
].fd
= pwm
->fd
;
1863 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1865 #ifdef WITH_PINENTRY
1866 case ASYNC_CMD_OPEN2
:
1867 case ASYNC_CMD_SAVE2
:
1868 /* The command has already completed (cached or new). */
1869 if (pwm
->state
== ASYNC_DONE
)
1872 if (pwm
->nb_fd
== -1)
1873 return GPG_ERR_INV_STATE
;
1876 fds
[fd
].fd
= pwm
->nb_fd
;
1877 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1882 if (!pwm
->tcp_conn
|| !pwm
->tcp_conn
->chan
)
1883 return GPG_ERR_INV_STATE
;
1885 n
= ares_getsock(pwm
->tcp_conn
->chan
, afds
, ARES_GETSOCK_MAXNUM
);
1887 for (i
= 0; i
< ARES_GETSOCK_MAXNUM
; i
++) {
1890 if (fd
> in_total
) {
1892 return GPG_ERR_ERANGE
;
1895 if (ARES_GETSOCK_READABLE(n
, i
)) {
1897 fds
[fd
].flags
|= PWMD_FD_READABLE
;
1900 if (ARES_GETSOCK_WRITABLE(n
, i
)) {
1902 fds
[fd
].flags
|= PWMD_FD_WRITABLE
;
1906 fds
[fd
++].fd
= afds
[i
];
1911 case ASYNC_CMD_CONNECT
:
1912 case ASYNC_CMD_HOSTKEY
:
1913 if (!pwm
->tcp_conn
|| pwm
->tcp_conn
->fd
== -1)
1914 return GPG_ERR_INV_STATE
;
1917 fds
[fd
].fd
= pwm
->tcp_conn
->fd
;
1918 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1923 return GPG_ERR_INV_STATE
;
1926 pwm_t
*pwmd_new(const char *name
)
1928 pwm_t
*h
= pwmd_calloc(1, sizeof(pwm_t
));
1934 h
->name
= pwmd_strdup(name
);
1943 h
->pinentry_timeout
= -30;
1944 h
->pinentry_tries
= 3;
1946 h
->prot
= PWMD_IP_ANY
;
1949 if (ttyname(STDOUT_FILENO
)) {
1952 ttyname_r(STDOUT_FILENO
, buf
, sizeof(buf
));
1953 h
->pinentry_tty
= pwmd_strdup(buf
);
1955 if (!h
->pinentry_tty
)
1959 if (getenv("TERM") && h
->pinentry_tty
) {
1960 h
->pinentry_term
= pwmd_strdup(getenv("TERM"));
1962 if (!h
->pinentry_term
)
1966 if (getenv("DISPLAY")) {
1967 h
->pinentry_display
= pwmd_strdup(getenv("DISPLAY"));
1969 if (!h
->pinentry_display
)
1980 void pwmd_free(void *ptr
)
1985 void *pwmd_malloc(size_t size
)
1987 return _xmalloc(size
);
1990 void *pwmd_calloc(size_t nmemb
, size_t size
)
1992 return _xcalloc(nmemb
, size
);
1995 void *pwmd_realloc(void *ptr
, size_t size
)
1997 return _xrealloc(ptr
, size
);
2000 char *pwmd_strdup(const char *str
)
2002 return _xstrdup(str
);
2005 char *pwmd_strdup_printf(const char *fmt
, ...)
2016 len
= vsnprintf(NULL
, 0, fmt
, ap
);
2018 buf
= pwmd_malloc(++len
);
2021 vsnprintf(buf
, len
, fmt
, ap2
);
2027 gpg_error_t
pwmd_getpin(pwm_t
*pwm
, const char *filename
, char **result
,
2028 pwmd_pinentry_t which
)
2030 #ifndef WITH_PINENTRY
2031 return GPG_ERR_NOT_IMPLEMENTED
;
2033 return _pwmd_getpin(pwm
, filename
, result
, which
);