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
);
64 static const char *_pwmd_strerror(gpg_error_t e
)
66 gpg_err_code_t code
= gpg_err_code(e
);
68 if (code
>= GPG_ERR_USER_1
&& code
< gpg_err_code(EPWMD_MAX
)) {
73 return N_("Unknown error");
75 return N_("No cache slots available");
77 return N_("Recursion loop");
79 return N_("No file is open");
81 return N_("General LibXML error");
83 return N_("File modified");
90 const char *pwmd_strerror(gpg_error_t code
)
92 const char *p
= _pwmd_strerror(code
);
94 return p
? p
: gpg_strerror(code
);
97 int pwmd_strerror_r(gpg_error_t code
, char *buf
, size_t size
)
99 const char *p
= _pwmd_strerror(code
);
102 snprintf(buf
, size
, "%s", p
);
104 if (strlen(p
) > size
)
110 return gpg_strerror_r(code
, buf
, size
);
113 gpg_error_t
pwmd_init()
115 static int initialized
;
124 bindtextdomain("libpwmd", LOCALEDIR
);
127 assuan_set_malloc_hooks(pwmd_malloc
, pwmd_realloc
, pwmd_free
);
128 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT
);
133 gpg_error_t
_connect_finalize(pwm_t
*pwm
)
136 int n
= assuan_get_active_fds(pwm
->ctx
, 0, active
, N_ARRAY(active
));
141 return GPG_ERR_EBADFD
;
147 assuan_set_pointer(pwm
->ctx
, pwm
);
150 // Until X11 forwarding is supported, disable the remote pwmd pinentry.
152 rc
= pwmd_command(pwm
, NULL
, "OPTION PINENTRY=0");
160 rc
= pwmd_command(pwm
, NULL
, "OPTION CLIENT NAME=%s", pwm
->name
);
166 rc
= pwmd_command(pwm
, &result
, "VERSION");
168 if (rc
&& rc
!= GPG_ERR_ASS_UNKNOWN_CMD
)
172 pwm
->version
= PWMD_V1
;
174 pwm
->version
= PWMD_V2
;
180 static gpg_error_t
_pwmd_connect_url(pwm_t
*pwm
, const char *url
, int async
)
182 char *p
= (char *)url
;
186 return GPG_ERR_INV_ARG
;
188 if (!p
|| !strncmp(p
, "socket://", 9)) {
194 else if (!strncmp(p
, "ssh://", 6) || !strncmp(p
, "ssh6://", 7) ||
195 !strncmp(p
, "ssh4://", 7)) {
197 return GPG_ERR_NOT_IMPLEMENTED
;
201 char *identity
= NULL
;
202 char *known_hosts
= NULL
;
203 char *username
= NULL
;
205 if (!strncmp(p
, "ssh6://", 7)) {
206 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV6
);
209 else if (!strncmp(p
, "ssh4://", 7)) {
210 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV4
);
214 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IP_ANY
);
221 rc
= _parse_ssh_url(p
, &host
, &port
, &username
, &identity
,
228 rc
= pwmd_ssh_connect_async(pwm
, host
, port
, identity
, username
,
231 rc
= pwmd_ssh_connect(pwm
, host
, port
, identity
, username
,
245 pwmd_free(known_hosts
);
252 rc
= pwmd_connect(pwm
, p
);
253 pwm
->state
= ASYNC_DONE
;
257 gpg_error_t
pwmd_connect_url(pwm_t
*pwm
, const char *url
)
259 return _pwmd_connect_url(pwm
, url
, 0);
262 gpg_error_t
pwmd_connect_url_async(pwm_t
*pwm
, const char *url
)
264 return _pwmd_connect_url(pwm
, url
, 1);
267 gpg_error_t
pwmd_connect(pwm_t
*pwm
, const char *path
)
269 char *socketpath
= NULL
;
270 assuan_context_t ctx
;
276 return GPG_ERR_INV_ARG
;
278 pwbuf
= _getpwuid(&pw
);
281 return gpg_error_from_errno(errno
);
284 socketpath
= pwmd_strdup_printf("%s/.pwmd/socket", pw
.pw_dir
);
286 socketpath
= _expand_homedir((char *)path
, &pw
);
291 return gpg_error_from_errno(ENOMEM
);
293 rc
= assuan_socket_connect_ext(&ctx
, socketpath
, -1, 0);
294 pwmd_free(socketpath
);
297 return gpg_err_code(rc
);
300 return _connect_finalize(pwm
);
303 static void disconnect(pwm_t
*pwm
)
305 if (!pwm
|| !pwm
->ctx
)
308 assuan_disconnect(pwm
->ctx
);
313 void pwmd_close(pwm_t
*pwm
)
321 pwmd_free(pwm
->password
);
324 pwmd_free(pwm
->title
);
327 pwmd_free(pwm
->desc
);
330 pwmd_free(pwm
->prompt
);
332 if (pwm
->pinentry_tty
)
333 pwmd_free(pwm
->pinentry_tty
);
335 if (pwm
->pinentry_display
)
336 pwmd_free(pwm
->pinentry_display
);
338 if (pwm
->pinentry_term
)
339 pwmd_free(pwm
->pinentry_term
);
342 pwmd_free(pwm
->lcctype
);
345 pwmd_free(pwm
->lcmessages
);
348 pwmd_free(pwm
->filename
);
351 pwmd_free(pwm
->name
);
355 _free_ssh_conn(pwm
->tcp_conn
);
361 gpg_error_t
pwmd_ssh_connect_async(pwm_t
*pwm
, const char *host
, int port
,
362 const char *identity
, const char *user
, const char *known_hosts
)
365 return GPG_ERR_NOT_IMPLEMENTED
;
367 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, identity
, user
,
368 known_hosts
, ASYNC_CMD_CONNECT
);
372 gpg_error_t
pwmd_ssh_connect(pwm_t
*pwm
, const char *host
, int port
,
373 const char *identity
, const char *user
, const char *known_hosts
)
376 return GPG_ERR_NOT_IMPLEMENTED
;
378 return _do_pwmd_ssh_connect(pwm
, host
, port
, identity
, user
, known_hosts
, 0);
382 gpg_error_t
pwmd_get_hostkey(pwm_t
*pwm
, const char *host
, int port
,
386 return GPG_ERR_NOT_IMPLEMENTED
;
391 rc
= _do_pwmd_ssh_connect(pwm
, host
, port
, NULL
, NULL
, NULL
, 1);
396 hostkey
= pwmd_strdup(pwm
->tcp_conn
->hostkey
);
399 rc
= gpg_error_from_errno(ENOMEM
);
406 gpg_error_t
pwmd_get_hostkey_async(pwm_t
*pwm
, const char *host
, int port
)
409 return GPG_ERR_NOT_IMPLEMENTED
;
411 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, NULL
, NULL
, NULL
,
416 static int inquire_realloc_cb(void *data
, const void *buffer
, size_t len
)
418 membuf_t
*mem
= (membuf_t
*)data
;
424 if ((p
= pwmd_realloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
425 return gpg_error_from_errno(ENOMEM
);
428 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
433 static int inquire_cb(void *data
, const char *keyword
)
435 pwm_t
*pwm
= (pwm_t
*)data
;
437 int flags
= fcntl(pwm
->fd
, F_GETFL
);
439 /* Shouldn't get this far without a callback. */
440 if (!pwm
->inquire_func
)
441 return GPG_ERR_INV_ARG
;
448 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
, &result
, &len
);
449 rc
= gpg_err_code(rc
);
451 if (rc
== GPG_ERR_EOF
|| !rc
) {
452 if (len
<= 0 || !result
) {
457 arc
= assuan_send_data(pwm
->ctx
, result
, len
);
458 arc
= gpg_err_code(arc
);
460 if (rc
== GPG_ERR_EOF
) {
471 /* Set to non-blocking so _pwmd_process() can return. */
472 fcntl(pwm
->fd
, F_SETFL
, O_NONBLOCK
);
473 rc
= _pwmd_process(pwm
);
474 fcntl(pwm
->fd
, F_SETFL
, flags
);
478 fcntl(pwm
->fd
, F_SETFL
, flags
);
479 return gpg_err_code(rc
);
482 static gpg_error_t
do_nb_command(pwm_t
*pwm
, const char *cmd
, ...)
489 if (pwm
->state
== ASYNC_DONE
)
490 pwm
->state
= ASYNC_INIT
;
492 if (pwm
->state
!= ASYNC_INIT
)
493 return GPG_ERR_INV_STATE
;
495 buf
= pwmd_malloc(ASSUAN_LINELENGTH
+1);
498 return gpg_error_from_errno(ENOMEM
);
501 len
= vsnprintf(buf
, ASSUAN_LINELENGTH
+1, cmd
, ap
);
504 if (len
>= ASSUAN_LINELENGTH
+1) {
506 return GPG_ERR_LINE_TOO_LONG
;
509 rc
= assuan_write_line(pwm
->ctx
, buf
);
513 pwm
->state
= ASYNC_PROCESS
;
515 return gpg_err_code(rc
);
518 gpg_error_t
pwmd_open_async(pwm_t
*pwm
, const char *filename
)
521 const char *f
= NULL
;
524 if (!pwm
|| !filename
)
525 return GPG_ERR_INV_ARG
;
528 return GPG_ERR_INV_STATE
;
530 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
531 return GPG_ERR_ASS_NESTED_COMMANDS
;
533 if (pwm
->lastcmd
== ASYNC_CMD_NONE
) {
537 pwmd_free(pwm
->filename
);
539 pwm
->filename
= pwmd_strdup(filename
);
542 return gpg_error_from_errno(ENOMEM
);
544 gpg_error_t rc
= send_pinentry_options(pwm
);
552 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN2
) {
556 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN
) {
557 rc
= set_pinentry_retry(pwm
);
566 return GPG_ERR_INV_STATE
;
568 pwm
->cmd
= ASYNC_CMD_OPEN
;
569 return do_nb_command(pwm
, "OPEN %s %s", f
, p
? p
: "");
572 gpg_error_t
pwmd_save_async(pwm_t
*pwm
)
577 return GPG_ERR_INV_ARG
;
580 return GPG_ERR_INV_STATE
;
582 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
583 return GPG_ERR_ASS_NESTED_COMMANDS
;
585 if (pwm
->lastcmd
!= ASYNC_CMD_SAVE2
) {
586 gpg_error_t rc
= send_pinentry_options(pwm
);
596 pwm
->cmd
= ASYNC_CMD_SAVE
;
597 return do_nb_command(pwm
, "SAVE %s", p
? p
: "");
600 static gpg_error_t
parse_assuan_line(pwm_t
*pwm
)
606 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
609 if (line
[0] == 'O' && line
[1] == 'K' &&
610 (line
[2] == 0 || line
[2] == ' ')) {
611 pwm
->state
= ASYNC_DONE
;
613 else if (line
[0] == '#') {
615 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' ')) {
616 if (pwm
->status_func
) {
617 rc
= pwm
->status_func(pwm
->status_data
,
618 line
[1] == 0 ? line
+1 : line
+2);
621 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
622 (line
[3] == 0 || line
[3] == ' ')) {
625 pwm
->state
= ASYNC_DONE
;
629 return gpg_err_code(rc
);
632 gpg_error_t
pwmd_pending_line(pwm_t
*pwm
)
635 return GPG_ERR_INV_ARG
;
638 return GPG_ERR_INV_STATE
;
640 return assuan_pending_line(pwm
->ctx
) ? 0 : GPG_ERR_NO_DATA
;
643 static pwmd_async_t
reset_async(pwm_t
*pwm
, int done
)
645 pwm
->state
= ASYNC_INIT
;
646 pwm
->cmd
= pwm
->lastcmd
= ASYNC_CMD_NONE
;
649 if (pwm
->nb_fd
!= -1) {
654 if (pwm
->_password
) {
655 pwmd_free(pwm
->_password
);
656 pwm
->_password
= NULL
;
660 if (done
&& pwm
->tcp_conn
) {
661 _free_ssh_conn(pwm
->tcp_conn
);
662 pwm
->tcp_conn
= NULL
;
670 * Used for processing status messages when not in an async command and for
671 * waiting for the result from pwmd_open_async() and pwmd_save_async().
673 static gpg_error_t
_pwmd_process(pwm_t
*pwm
)
677 struct timeval tv
= {0, 0};
681 FD_SET(pwm
->fd
, &fds
);
683 n
= pth_select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
685 n
= select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
689 return gpg_error_from_syserror();
692 if (FD_ISSET(pwm
->fd
, &fds
))
693 rc
= parse_assuan_line(pwm
);
696 while (!rc
&& assuan_pending_line(pwm
->ctx
))
697 rc
= parse_assuan_line(pwm
);
699 return gpg_err_code(rc
);
702 static void reset_handle(pwm_t
*h
)
707 _pinentry_disconnect(h
);
715 gpg_error_t
pwmd_disconnect(pwm_t
*pwm
)
718 return GPG_ERR_INV_ARG
;
721 if (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1)
725 return GPG_ERR_INV_STATE
;
731 _ssh_disconnect(pwm
);
738 pwmd_async_t
pwmd_process(pwm_t
*pwm
, gpg_error_t
*rc
, char **result
)
740 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
743 struct timeval tv
= {0, 0};
750 return GPG_ERR_INV_ARG
;
755 *rc
= GPG_ERR_INV_ARG
;
758 else if (!pwm
->ctx
) {
761 *rc
= GPG_ERR_INV_STATE
;
765 case ASYNC_CMD_CONNECT
:
766 case ASYNC_CMD_HOSTKEY
:
772 /* When not in a command, this will let libassuan process status messages
773 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
774 * descriptor returned by pwmd_get_fd() to determine when this should be
775 * called or call pwmd_pending_line() to determine whether a buffered line
776 * needs to be processed. */
777 if (pwm
->cmd
== ASYNC_CMD_NONE
) {
778 *rc
= _pwmd_process(pwm
);
782 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
783 if (pwm
->state
== ASYNC_DONE
) {
784 *rc
= _pwmd_process(pwm
);
785 return reset_async(pwm
, 0);
788 if (pwm
->state
!= ASYNC_PROCESS
) {
789 *rc
= GPG_ERR_INV_STATE
;
794 if (pwm
->cmd
== ASYNC_CMD_DNS
) {
797 if (pwm
->tcp_conn
->rc
) {
798 *rc
= pwm
->tcp_conn
->rc
;
799 return reset_async(pwm
, 1);
804 n
= ares_fds(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
806 /* Shouldn't happen. */
811 n
= pth_select(n
, &rfds
, &wfds
, NULL
, &tv
);
813 n
= select(n
, &rfds
, &wfds
, NULL
, &tv
);
817 *rc
= gpg_error_from_syserror();
818 return reset_async(pwm
, 1);
822 ares_process(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
826 else if (pwm
->cmd
== ASYNC_CMD_CONNECT
) {
827 if (pwm
->tcp_conn
->rc
== GPG_ERR_EINPROGRESS
) {
829 socklen_t len
= sizeof(int);
832 FD_SET(pwm
->tcp_conn
->fd
, &fds
);
834 n
= pth_select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
836 n
= select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
839 if (!n
|| !FD_ISSET(pwm
->tcp_conn
->fd
, &fds
))
842 *rc
= gpg_error_from_syserror();
843 return reset_async(pwm
, 1);
846 ret
= getsockopt(pwm
->tcp_conn
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
849 *rc
= ret
? gpg_error_from_syserror() : gpg_error_from_errno(n
);
850 return reset_async(pwm
, 1);
853 else if (pwm
->tcp_conn
->rc
) {
854 *rc
= pwm
->tcp_conn
->rc
;
855 return reset_async(pwm
, 1);
858 fcntl(pwm
->tcp_conn
->fd
, F_SETFL
, 0);
859 *rc
= _setup_ssh_session(pwm
);
862 switch (pwm
->tcp_conn
->cmd
) {
863 case ASYNC_CMD_HOSTKEY
:
864 *result
= pwm
->result
;
871 return reset_async(pwm
, *rc
? 1 : 0);
876 if (pwm
->cmd
== ASYNC_CMD_OPEN2
|| pwm
->cmd
== ASYNC_CMD_SAVE2
) {
879 if (pwm
->nb_fd
== -1) {
880 *rc
= GPG_ERR_INV_STATE
;
881 return reset_async(pwm
, 0);
885 FD_SET(pwm
->nb_fd
, &fds
);
886 FD_SET(pwm
->fd
, &fds
);
888 n
= pth_select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
890 n
= select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
893 *rc
= gpg_error_from_syserror();
894 return reset_async(pwm
, 0);
897 if (n
> 0 && FD_ISSET(pwm
->nb_fd
, &fds
)) {
900 size_t len
= pth_read(pwm
->nb_fd
, &nb
, sizeof(nb
));
902 size_t len
= read(pwm
->nb_fd
, &nb
, sizeof(nb
));
904 waitpid(pwm
->nb_pid
, &status
, WNOHANG
);
906 if (len
!= sizeof(nb
)) {
907 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
908 *rc
= gpg_error_from_syserror();
909 return reset_async(pwm
, 0);
915 return reset_async(pwm
, 0);
917 /* Since the non-blocking pinentry returned a success, do a
918 * non-blocking OPEN or SAVE. */
919 pwmd_async_cmd_t c
= pwm
->cmd
;
921 pwm
->_password
= pwmd_strdup(nb
.password
);
922 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
925 if (!pwm
->_password
) {
926 *rc
= gpg_error_from_errno(ENOMEM
);
927 return reset_async(pwm
, 0);
930 if (c
== ASYNC_CMD_SAVE2
)
931 *rc
= pwmd_save_async(pwm
);
933 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
940 return ASYNC_PROCESS
;
943 /* Fall through so status messages can be processed during the
949 *rc
= GPG_ERR_INV_STATE
;
950 return reset_async(pwm
, 0);
953 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
955 *rc
= _pwmd_process(pwm
);
957 if (*rc
&& *rc
!= GPG_ERR_INV_PASSPHRASE
)
958 return reset_async(pwm
, 0);
961 if (!pwm
->tcp_conn
&& pwm
->cmd
== ASYNC_CMD_OPEN
&&
963 if (pwm
->cmd
== ASYNC_CMD_OPEN
&&
965 *rc
== GPG_ERR_INV_PASSPHRASE
&&
966 ++pwm
->pin_try
< pwm
->pinentry_tries
) {
967 if (pwm
->_password
) {
969 pwm
->lastcmd
= ASYNC_CMD_OPEN2
;
970 *rc
= pwmd_open_async2(pwm
, pwm
->filename
);
974 pwm
->lastcmd
= ASYNC_CMD_OPEN
;
975 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
979 if (*rc
|| pwm
->state
== ASYNC_DONE
)
980 return reset_async(pwm
, 0);
985 gpg_error_t
_assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
986 char **result
, const char *cmd
)
992 return GPG_ERR_INV_ARG
;
994 if (strlen(cmd
) >= ASSUAN_LINELENGTH
+1)
995 return GPG_ERR_LINE_TOO_LONG
;
999 rc
= assuan_transact(ctx
, cmd
, inquire_realloc_cb
, &data
,
1001 pwm
->pctx
== ctx
? pwm
->_inquire_func
: inquire_cb
,
1002 pwm
->pctx
== ctx
? pwm
->_inquire_data
: pwm
,
1006 pwm
->status_func
, pwm
->status_data
);
1010 pwmd_free(data
.buf
);
1016 inquire_realloc_cb(&data
, "", 1);
1019 pwmd_free(data
.buf
);
1020 rc
= GPG_ERR_INV_ARG
;
1023 *result
= (char *)data
.buf
;
1027 return gpg_err_code(rc
);
1030 gpg_error_t
pwmd_inquire(pwm_t
*pwm
, const char *cmd
, pwmd_inquire_cb_t fn
,
1033 if (!pwm
|| !cmd
|| !fn
)
1034 return GPG_ERR_INV_ARG
;
1037 return GPG_ERR_INV_STATE
;
1039 pwm
->inquire_func
= fn
;
1040 pwm
->inquire_data
= data
;
1041 return _assuan_command(pwm
, pwm
->ctx
, NULL
, cmd
);
1044 gpg_error_t
pwmd_command_ap(pwm_t
*pwm
, char **result
, const char *cmd
,
1052 return GPG_ERR_INV_ARG
;
1055 return GPG_ERR_INV_STATE
;
1058 * C99 allows the dst pointer to be null which will calculate the length
1059 * of the would-be result and return it.
1062 len
= vsnprintf(NULL
, 0, cmd
, ap
)+1;
1063 buf
= (char *)pwmd_malloc(len
);
1067 return gpg_error_from_errno(ENOMEM
);
1070 len
= vsnprintf(buf
, len
, cmd
, ap2
);
1073 if (buf
[strlen(buf
)-1] == '\n')
1074 buf
[strlen(buf
)-1] = 0;
1076 if (buf
[strlen(buf
)-1] == '\r')
1077 buf
[strlen(buf
)-1] = 0;
1079 gpg_error_t rc
= _assuan_command(pwm
, pwm
->ctx
, result
, buf
);
1084 gpg_error_t
pwmd_command(pwm_t
*pwm
, char **result
, const char *cmd
, ...)
1089 return GPG_ERR_INV_ARG
;
1092 return GPG_ERR_INV_STATE
;
1098 gpg_error_t rc
= pwmd_command_ap(pwm
, result
, cmd
, ap
);
1103 static gpg_error_t
send_pinentry_options(pwm_t
*pwm
)
1107 if (pwm
->pinentry_path
) {
1108 rc
= pwmd_command(pwm
, NULL
, "OPTION PATH=%s", pwm
->pinentry_path
);
1114 if (pwm
->pinentry_tty
) {
1115 rc
= pwmd_command(pwm
, NULL
, "OPTION TTYNAME=%s", pwm
->pinentry_tty
);
1121 if (pwm
->pinentry_term
) {
1122 rc
= pwmd_command(pwm
, NULL
, "OPTION TTYTYPE=%s", pwm
->pinentry_term
);
1128 if (pwm
->pinentry_display
) {
1129 rc
= pwmd_command(pwm
, NULL
, "OPTION DISPLAY=%s",
1130 pwm
->pinentry_display
);
1137 rc
= pwmd_command(pwm
, NULL
, "OPTION TITLE=%s", pwm
->title
);
1144 rc
= pwmd_command(pwm
, NULL
, "OPTION DESC=%s", pwm
->desc
);
1151 rc
= pwmd_command(pwm
, NULL
, "OPTION PROMPT=%s", pwm
->prompt
);
1158 rc
= pwmd_command(pwm
, NULL
, "OPTION LC_CTYPE=%s", pwm
->lcctype
);
1164 if (pwm
->lcmessages
) {
1165 rc
= pwmd_command(pwm
, NULL
, "OPTION LC_MESSAGES=%s", pwm
->lcmessages
);
1171 if (pwm
->pinentry_timeout
>= 0 && !pwm
->pin_try
) {
1172 rc
= pwmd_command(pwm
, NULL
, "OPTION TIMEOUT=%i", pwm
->pinentry_timeout
);
1181 gpg_error_t
pwmd_socket_type(pwm_t
*pwm
, pwmd_socket_t
*result
)
1183 if (!pwm
|| !result
)
1184 return GPG_ERR_INV_ARG
;
1187 if (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1)
1191 return GPG_ERR_INV_STATE
;
1194 *result
= pwm
->tcp_conn
? PWMD_SOCKET_SSH
: PWMD_SOCKET_UDS
;
1196 *result
= PWMD_SOCKET_UDS
;
1201 static gpg_error_t
set_pinentry_retry(pwm_t
*pwm
)
1205 if (pwm
->pin_try
== 1) {
1206 rc
= pwmd_command(pwm
, NULL
, "OPTION TITLE=%s",
1207 N_("Invalid passphrase, please try again."));
1212 rc
= pwmd_command(pwm
, NULL
, "OPTION TIMEOUT=0");
1218 static gpg_error_t
do_pwmd_open(pwm_t
*pwm
, const char *filename
, int nb
,
1221 char *result
= NULL
;
1222 char *password
= NULL
;
1226 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1229 if (!pwm
|| !filename
|| !*filename
)
1230 return GPG_ERR_INV_ARG
;
1233 return GPG_ERR_INV_STATE
;
1236 * Avoid calling pinentry if the password is cached on the server or if
1237 * this is a new file. pwmd version 2 adds a VERSION command which is
1238 * determined in _connect_finalize(). If the server is version 2,
1239 * ISCACHED will return GPG_ERR_ENOENT if it doesn't exist.
1242 /* Don't try a local filesystem lookup of the data file over a remote
1244 if (!pwm
->tcp_conn
&& pwm
->version
== PWMD_V1
) {
1246 if (pwm
->version
== PWMD_V1
) {
1248 rc
= pwmd_command(pwm
, &result
, "GETCONFIG data_directory");
1253 path
= pwmd_strdup_printf("%s/%s", result
, filename
);
1257 return gpg_error_from_errno(ENOMEM
);
1259 if (access(path
, R_OK
) == -1) {
1260 if (errno
== ENOENT
) {
1269 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", filename
);
1271 /* pwmd >= 2.0 specific. This is a new file which doesn't require a
1273 if (rc
== GPG_ERR_ENOENT
)
1276 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1279 if (rc
== GPG_ERR_NOT_FOUND
) {
1280 if (pwm
->password
) {
1281 password
= pwm
->password
;
1285 if (pwm
->passfunc
) {
1286 rc
= pwm
->passfunc(pwm
->passdata
, &password
);
1295 #ifdef WITH_PINENTRY
1296 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1297 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1298 if (!pwm
->pin_try
) {
1299 rc
= pwmd_command(pwm
, NULL
, "OPTION PINENTRY=0");
1305 rc
= _pinentry_open(pwm
, filename
, &password
, nb
);
1307 /* pwmd_process() should be called if using a non-blocking local
1309 if (rc
|| (!rc
&& nb
))
1315 pwm
->state
= ASYNC_DONE
;
1318 if (!local_pinentry
&& !pwm
->tcp_conn
&& !pwm
->pin_try
) {
1320 if (!local_pinentry
&& !pwm
->pin_try
) {
1322 rc
= send_pinentry_options(pwm
);
1328 rc
= pwmd_command(pwm
, NULL
, "OPEN %s %s", filename
,
1329 password
? password
: "");
1332 * Keep the user defined password set with pwmd_setopt(). The password may
1333 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1335 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1336 pwmd_free(password
);
1338 if (rc
== GPG_ERR_INV_PASSPHRASE
) {
1339 if (++pwm
->pin_try
< pwm
->pinentry_tries
&& !nb
) {
1342 #ifdef WITH_PINENTRY
1344 rc
= _getpin(pwm
, &password
, PINENTRY_OPEN_FAILED
);
1346 else if (!pwm
->tcp_conn
) {
1352 if (!pwm
->tcp_conn
) {
1355 rc
= set_pinentry_retry(pwm
);
1363 #ifdef WITH_PINENTRY
1364 else if (local_pinentry
&& !nb
)
1365 _pinentry_disconnect(pwm
);
1370 #ifdef WITH_PINENTRY
1371 else if (rc
&& local_pinentry
&& !nb
)
1372 _pinentry_disconnect(pwm
);
1377 pwmd_free(pwm
->filename
);
1379 pwm
->filename
= pwmd_strdup(filename
);
1385 gpg_error_t
pwmd_open2(pwm_t
*pwm
, const char *filename
)
1387 #ifndef WITH_PINENTRY
1388 return GPG_ERR_NOT_IMPLEMENTED
;
1390 return do_pwmd_open(pwm
, filename
, 0, 1);
1394 gpg_error_t
pwmd_open(pwm_t
*pwm
, const char *filename
)
1396 return do_pwmd_open(pwm
, filename
, 0, 0);
1399 gpg_error_t
pwmd_open_async2(pwm_t
*pwm
, const char *filename
)
1401 #ifndef WITH_PINENTRY
1402 return GPG_ERR_NOT_IMPLEMENTED
;
1404 if (!pwm
|| !filename
)
1405 return GPG_ERR_INV_ARG
;
1408 return GPG_ERR_INV_STATE
;
1410 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1411 return GPG_ERR_ASS_NESTED_COMMANDS
;
1413 /* Initialize a new command since this is not a pinentry retry. */
1414 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1417 pwm
->cmd
= ASYNC_CMD_OPEN2
;
1418 pwm
->state
= ASYNC_PROCESS
;
1419 gpg_error_t rc
= do_pwmd_open(pwm
, filename
, 1, 1);
1422 reset_async(pwm
, 0);
1428 static gpg_error_t
do_pwmd_save(pwm_t
*pwm
, int nb
, int local_pinentry
)
1430 char *result
= NULL
;
1431 char *password
= NULL
;
1435 return GPG_ERR_INV_ARG
;
1438 return GPG_ERR_INV_STATE
;
1440 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", pwm
->filename
);
1442 if (rc
== GPG_ERR_ENOENT
)
1443 rc
= GPG_ERR_NOT_FOUND
;
1445 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1448 if (rc
== GPG_ERR_NOT_FOUND
) {
1449 if (pwm
->password
) {
1450 password
= pwm
->password
;
1454 if (pwm
->passfunc
) {
1455 rc
= pwm
->passfunc(pwm
->passdata
, &password
);
1464 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1465 #ifdef WITH_PINENTRY
1466 /* Get the password using the LOCAL pinentry. */
1470 pwmd_nb_status_t pw
;
1473 return gpg_error_from_syserror();
1486 pw
.error
= _do_save_getpin(pwm
, &password
);
1489 snprintf(pw
.password
, sizeof(pw
.password
), "%s",
1491 pwmd_free(password
);
1494 pth_write(p
[1], &pw
, sizeof(pw
));
1496 write(p
[1], &pw
, sizeof(pw
));
1498 memset(&pw
, 0, sizeof(pw
));
1503 rc
= gpg_error_from_syserror();
1517 rc
= _do_save_getpin(pwm
, &password
);
1524 pwm
->state
= ASYNC_DONE
;
1528 if (!local_pinentry
&& !pwm
->tcp_conn
) {
1530 if (!local_pinentry
) {
1532 rc
= send_pinentry_options(pwm
);
1538 rc
= pwmd_command(pwm
, NULL
, "SAVE %s", password
? password
: "");
1540 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1541 pwmd_free(password
);
1546 gpg_error_t
pwmd_save_async2(pwm_t
*pwm
)
1548 #ifndef WITH_PINENTRY
1549 return GPG_ERR_NOT_IMPLEMENTED
;
1552 return GPG_ERR_INV_ARG
;
1555 return GPG_ERR_INV_STATE
;
1557 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1558 return GPG_ERR_ASS_NESTED_COMMANDS
;
1560 pwm
->cmd
= ASYNC_CMD_SAVE2
;
1561 pwm
->state
= ASYNC_PROCESS
;
1562 gpg_error_t rc
= do_pwmd_save(pwm
, 1, 1);
1565 reset_async(pwm
, 0);
1571 gpg_error_t
pwmd_save2(pwm_t
*pwm
)
1573 #ifndef WITH_PINENTRY
1574 return GPG_ERR_NOT_IMPLEMENTED
;
1576 return do_pwmd_save(pwm
, 0, 1);
1580 gpg_error_t
pwmd_save(pwm_t
*pwm
)
1582 return do_pwmd_save(pwm
, 0, 0);
1585 gpg_error_t
pwmd_setopt(pwm_t
*pwm
, pwmd_option_t opt
, ...)
1588 int n
= va_arg(ap
, int);
1593 return GPG_ERR_INV_ARG
;
1598 case PWMD_OPTION_STATUS_CB
:
1599 pwm
->status_func
= va_arg(ap
, pwmd_status_cb_t
);
1601 case PWMD_OPTION_STATUS_DATA
:
1602 pwm
->status_data
= va_arg(ap
, void *);
1604 case PWMD_OPTION_PASSPHRASE_CB
:
1605 pwm
->passfunc
= va_arg(ap
, pwmd_passphrase_cb_t
);
1607 case PWMD_OPTION_PASSPHRASE_DATA
:
1608 pwm
->passdata
= va_arg(ap
, void *);
1610 case PWMD_OPTION_PASSPHRASE
:
1611 arg1
= va_arg(ap
, char *);
1614 pwmd_free(pwm
->password
);
1616 pwm
->password
= pwmd_strdup(arg1
);
1618 case PWMD_OPTION_PINENTRY_TRIES
:
1619 n
= va_arg(ap
, int);
1623 rc
= GPG_ERR_INV_VALUE
;
1626 pwm
->pinentry_tries
= n
;
1628 case PWMD_OPTION_PINENTRY_TIMEOUT
:
1629 n
= va_arg(ap
, int);
1633 rc
= GPG_ERR_INV_VALUE
;
1636 pwm
->pinentry_timeout
= n
;
1638 case PWMD_OPTION_PINENTRY_PATH
:
1639 if (pwm
->pinentry_path
)
1640 pwmd_free(pwm
->pinentry_path
);
1642 pwm
->pinentry_path
= _expand_homedir(va_arg(ap
, char *), NULL
);
1644 case PWMD_OPTION_PINENTRY_TTY
:
1645 if (pwm
->pinentry_tty
)
1646 pwmd_free(pwm
->pinentry_tty
);
1648 pwm
->pinentry_tty
= pwmd_strdup(va_arg(ap
, char *));
1650 case PWMD_OPTION_PINENTRY_DISPLAY
:
1651 if (pwm
->pinentry_display
)
1652 pwmd_free(pwm
->pinentry_display
);
1654 pwm
->pinentry_display
= pwmd_strdup(va_arg(ap
, char *));
1656 case PWMD_OPTION_PINENTRY_TERM
:
1657 if (pwm
->pinentry_term
)
1658 pwmd_free(pwm
->pinentry_term
);
1660 pwm
->pinentry_term
= pwmd_strdup(va_arg(ap
, char *));
1662 case PWMD_OPTION_PINENTRY_TITLE
:
1664 pwmd_free(pwm
->title
);
1666 pwm
->title
= _percent_escape(va_arg(ap
, char *));
1668 case PWMD_OPTION_PINENTRY_PROMPT
:
1670 pwmd_free(pwm
->prompt
);
1672 pwm
->prompt
= _percent_escape(va_arg(ap
, char *));
1674 case PWMD_OPTION_PINENTRY_DESC
:
1676 pwmd_free(pwm
->desc
);
1678 pwm
->desc
= _percent_escape(va_arg(ap
, char *));
1680 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
1682 pwmd_free(pwm
->lcctype
);
1684 pwm
->lcctype
= pwmd_strdup(va_arg(ap
, char *));
1686 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
1687 if (pwm
->lcmessages
)
1688 pwmd_free(pwm
->lcmessages
);
1690 pwm
->lcmessages
= pwmd_strdup(va_arg(ap
, char *));
1692 case PWMD_OPTION_IP_VERSION
:
1694 n
= va_arg(ap
, int);
1703 rc
= GPG_ERR_INV_VALUE
;
1709 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1713 rc
= GPG_ERR_UNKNOWN_OPTION
;
1721 gpg_error_t
pwmd_get_fds(pwm_t
*pwm
, pwmd_fd_t
*fds
, int *n_fds
)
1726 int afds
[ARES_GETSOCK_MAXNUM
];
1731 if (!pwm
|| !fds
|| !n_fds
|| *n_fds
<= 0)
1732 return GPG_ERR_INV_ARG
;
1736 memset(afds
, 0, sizeof(int)*ARES_GETSOCK_MAXNUM
);
1738 memset(fds
, 0, sizeof(pwmd_fd_t
)*in_total
);
1743 case ASYNC_CMD_NONE
:
1744 case ASYNC_CMD_OPEN
:
1745 case ASYNC_CMD_SAVE
:
1746 #ifdef WITH_PINENTRY
1750 return GPG_ERR_INV_STATE
;
1753 fds
[fd
].fd
= pwm
->fd
;
1754 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1756 #ifdef WITH_PINENTRY
1757 case ASYNC_CMD_OPEN2
:
1758 case ASYNC_CMD_SAVE2
:
1759 /* The command has already completed (cached or new). */
1760 if (pwm
->state
== ASYNC_DONE
)
1763 if (pwm
->nb_fd
== -1)
1764 return GPG_ERR_INV_STATE
;
1767 fds
[fd
].fd
= pwm
->nb_fd
;
1768 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1773 if (!pwm
->tcp_conn
|| !pwm
->tcp_conn
->chan
)
1774 return GPG_ERR_INV_STATE
;
1776 n
= ares_getsock(pwm
->tcp_conn
->chan
, afds
, ARES_GETSOCK_MAXNUM
);
1778 for (i
= 0; i
< ARES_GETSOCK_MAXNUM
; i
++) {
1781 if (fd
> in_total
) {
1783 return GPG_ERR_ERANGE
;
1786 if (ARES_GETSOCK_READABLE(n
, i
)) {
1788 fds
[fd
].flags
|= PWMD_FD_READABLE
;
1791 if (ARES_GETSOCK_WRITABLE(n
, i
)) {
1793 fds
[fd
].flags
|= PWMD_FD_WRITABLE
;
1797 fds
[fd
++].fd
= afds
[i
];
1802 case ASYNC_CMD_CONNECT
:
1803 case ASYNC_CMD_HOSTKEY
:
1804 if (!pwm
->tcp_conn
|| pwm
->tcp_conn
->fd
== -1)
1805 return GPG_ERR_INV_STATE
;
1808 fds
[fd
].fd
= pwm
->tcp_conn
->fd
;
1809 fds
[fd
++].flags
= PWMD_FD_READABLE
;
1814 return GPG_ERR_INV_STATE
;
1817 pwm_t
*pwmd_new(const char *name
)
1819 pwm_t
*h
= pwmd_calloc(1, sizeof(pwm_t
));
1825 h
->name
= pwmd_strdup(name
);
1834 h
->pinentry_timeout
= -30;
1835 h
->pinentry_tries
= 3;
1837 h
->prot
= PWMD_IP_ANY
;
1840 if (ttyname(STDOUT_FILENO
)) {
1843 ttyname_r(STDOUT_FILENO
, buf
, sizeof(buf
));
1844 h
->pinentry_tty
= pwmd_strdup(buf
);
1846 if (!h
->pinentry_tty
)
1850 if (getenv("TERM") && h
->pinentry_tty
) {
1851 h
->pinentry_term
= pwmd_strdup(getenv("TERM"));
1853 if (!h
->pinentry_term
)
1857 if (getenv("DISPLAY")) {
1858 h
->pinentry_display
= pwmd_strdup(getenv("DISPLAY"));
1860 if (!h
->pinentry_display
)
1871 void pwmd_free(void *ptr
)
1876 void *pwmd_malloc(size_t size
)
1878 return _xmalloc(size
);
1881 void *pwmd_calloc(size_t nmemb
, size_t size
)
1883 return _xcalloc(nmemb
, size
);
1886 void *pwmd_realloc(void *ptr
, size_t size
)
1888 return _xrealloc(ptr
, size
);
1891 char *pwmd_strdup(const char *str
)
1893 return _xstrdup(str
);
1896 char *pwmd_strdup_printf(const char *fmt
, ...)
1907 len
= vsnprintf(NULL
, 0, fmt
, ap
);
1909 buf
= pwmd_malloc(++len
);
1912 vsnprintf(buf
, len
, fmt
, ap2
);