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
30 #include <sys/socket.h>
39 #include <sys/types.h>
41 #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
);
99 if (strlen(p
)+1 > size
)
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
);
148 pwm
->tcp_conn
->state
= SSH_NONE
;
152 rc
= pwmd_command(pwm
, NULL
, "SET NAME=%s", pwm
->name
);
161 static gpg_error_t
_pwmd_connect_url(pwm_t
*pwm
, const char *url
, int async
)
163 char *p
= (char *)url
;
167 return GPG_ERR_INV_ARG
;
169 if (!p
|| !strncmp(p
, "file://", 7) || !strncmp(p
, "local://", 8)) {
171 if (!strncmp(p
, "file://", 7))
179 else if (!strncmp(p
, "ssh://", 6) || !strncmp(p
, "ssh6://", 7) ||
180 !strncmp(p
, "ssh4://", 7)) {
182 return GPG_ERR_NOT_IMPLEMENTED
;
186 char *identity
= NULL
;
187 char *known_hosts
= NULL
;
188 char *username
= NULL
;
190 if (!strncmp(p
, "ssh6://", 7)) {
191 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV6
);
194 else if (!strncmp(p
, "ssh4://", 7)) {
195 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IPV4
);
199 rc
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, PWMD_IP_ANY
);
206 rc
= _parse_ssh_url(p
, &host
, &port
, &username
, &identity
,
213 rc
= pwmd_ssh_connect_async(pwm
, host
, port
, identity
, username
,
216 rc
= pwmd_ssh_connect(pwm
, host
, port
, identity
, username
,
230 pwmd_free(known_hosts
);
237 rc
= pwmd_connect(pwm
, p
);
238 pwm
->state
= ASYNC_DONE
;
242 gpg_error_t
pwmd_connect_url(pwm_t
*pwm
, const char *url
)
244 return _pwmd_connect_url(pwm
, url
, 0);
247 gpg_error_t
pwmd_connect_url_async(pwm_t
*pwm
, const char *url
)
249 return _pwmd_connect_url(pwm
, url
, 1);
252 gpg_error_t
pwmd_connect(pwm_t
*pwm
, const char *path
)
254 char *socketpath
= NULL
;
255 assuan_context_t ctx
;
261 return GPG_ERR_INV_ARG
;
263 pwbuf
= _getpwuid(&pw
);
266 return gpg_error_from_syserror();
269 socketpath
= pwmd_strdup_printf("%s/.pwmd/socket", pw
.pw_dir
);
271 socketpath
= _expand_homedir((char *)path
, &pw
);
276 return GPG_ERR_ENOMEM
;
278 rc
= assuan_socket_connect_ext(&ctx
, socketpath
, -1, 0);
279 pwmd_free(socketpath
);
282 return gpg_err_code(rc
);
285 return _connect_finalize(pwm
);
288 static void disconnect(pwm_t
*pwm
)
290 if (!pwm
|| !pwm
->ctx
)
293 assuan_disconnect(pwm
->ctx
);
298 void pwmd_close(pwm_t
*pwm
)
306 pwmd_free(pwm
->password
);
309 pwmd_free(pwm
->title
);
312 pwmd_free(pwm
->desc
);
315 pwmd_free(pwm
->prompt
);
317 if (pwm
->pinentry_tty
)
318 pwmd_free(pwm
->pinentry_tty
);
320 if (pwm
->pinentry_display
)
321 pwmd_free(pwm
->pinentry_display
);
323 if (pwm
->pinentry_term
)
324 pwmd_free(pwm
->pinentry_term
);
327 pwmd_free(pwm
->lcctype
);
330 pwmd_free(pwm
->lcmessages
);
333 pwmd_free(pwm
->filename
);
336 pwmd_free(pwm
->name
);
339 pwmd_free(pwm
->cipher
);
343 _free_ssh_conn(pwm
->tcp_conn
);
348 _pinentry_disconnect(pwm
);
355 static gpg_error_t
do_async_command(pwm_t
*pwm
, char **result
)
361 s
= pwmd_process(pwm
, &rc
, result
);
363 if (s
!= ASYNC_DONE
) {
370 } while (s
!= ASYNC_DONE
);
376 gpg_error_t
pwmd_ssh_connect_async(pwm_t
*pwm
, const char *host
, int port
,
377 const char *identity
, const char *user
, const char *known_hosts
)
380 return GPG_ERR_NOT_IMPLEMENTED
;
382 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, identity
, user
,
383 known_hosts
, ASYNC_CMD_CONNECT
);
387 gpg_error_t
pwmd_ssh_connect(pwm_t
*pwm
, const char *host
, int port
,
388 const char *identity
, const char *user
, const char *known_hosts
)
391 return GPG_ERR_NOT_IMPLEMENTED
;
395 rc
= _do_pwmd_ssh_connect_async(pwm
, host
, port
, identity
, user
,
396 known_hosts
, ASYNC_CMD_CONNECT
);
397 return rc
? rc
: do_async_command(pwm
, NULL
);
401 gpg_error_t
pwmd_get_hostkey(pwm_t
*pwm
, const char *host
, int port
,
405 return GPG_ERR_NOT_IMPLEMENTED
;
409 rc
= _do_pwmd_ssh_connect_async(pwm
, host
, port
, NULL
, NULL
, NULL
,
412 return rc
? rc
: do_async_command(pwm
, result
);
416 gpg_error_t
pwmd_get_hostkey_async(pwm_t
*pwm
, const char *host
, int port
)
419 return GPG_ERR_NOT_IMPLEMENTED
;
421 return _do_pwmd_ssh_connect_async(pwm
, host
, port
, NULL
, NULL
, NULL
,
426 static int inquire_realloc_cb(void *data
, const void *buffer
, size_t len
)
428 membuf_t
*mem
= (membuf_t
*)data
;
434 if ((p
= pwmd_realloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
435 return GPG_ERR_ENOMEM
;
438 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
443 static int inquire_cb(void *data
, const char *keyword
)
445 pwm_t
*pwm
= (pwm_t
*)data
;
448 /* Shouldn't get this far without a callback. */
449 if (!pwm
->inquire_func
)
450 return GPG_ERR_INV_ARG
;
457 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
, &result
, &len
);
458 rc
= gpg_err_code(rc
);
460 if (rc
== GPG_ERR_EOF
|| !rc
) {
461 if (len
<= 0 && !result
) {
465 else if ((len
<= 0 && result
) || (len
&& !result
)) {
466 rc
= GPG_ERR_INV_ARG
;
470 arc
= assuan_send_data(pwm
->ctx
, result
, len
);
471 arc
= gpg_err_code(arc
);
473 if (rc
== GPG_ERR_EOF
) {
484 pwm
->inquire_sent
+= len
;
486 if (pwm
->status_func
) {
487 char buf
[ASSUAN_LINELENGTH
];
489 snprintf(buf
, sizeof(buf
), "XFER %u %u", pwm
->inquire_sent
,
491 rc
= pwm
->status_func(pwm
->status_data
, buf
);
497 rc
= _pwmd_process(pwm
);
499 if (rc
== GPG_ERR_EAGAIN
)
504 return gpg_err_code(rc
);
507 static gpg_error_t
do_nb_command(pwm_t
*pwm
, const char *cmd
, ...)
514 if (pwm
->state
== ASYNC_DONE
)
515 pwm
->state
= ASYNC_INIT
;
517 if (pwm
->state
!= ASYNC_INIT
)
518 return GPG_ERR_INV_STATE
;
520 buf
= pwmd_malloc(ASSUAN_LINELENGTH
+1);
523 return GPG_ERR_ENOMEM
;
526 len
= vsnprintf(buf
, ASSUAN_LINELENGTH
+1, cmd
, ap
);
529 if (len
>= ASSUAN_LINELENGTH
+1) {
531 return GPG_ERR_LINE_TOO_LONG
;
534 rc
= assuan_write_line(pwm
->ctx
, buf
);
538 pwm
->state
= ASYNC_PROCESS
;
540 return gpg_err_code(rc
);
543 gpg_error_t
pwmd_open_async(pwm_t
*pwm
, const char *filename
)
546 const char *f
= NULL
;
549 if (!pwm
|| !filename
)
550 return GPG_ERR_INV_ARG
;
553 return GPG_ERR_INV_STATE
;
555 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
556 return GPG_ERR_ASS_NESTED_COMMANDS
;
558 if (pwm
->lastcmd
== ASYNC_CMD_NONE
) {
562 pwmd_free(pwm
->filename
);
564 pwm
->filename
= pwmd_strdup(filename
);
567 return GPG_ERR_ENOMEM
;
569 gpg_error_t rc
= send_pinentry_options(pwm
);
574 rc
= get_custom_passphrase(pwm
, &p
);
576 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
582 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN2
) {
587 else if (pwm
->lastcmd
== ASYNC_CMD_OPEN
) {
588 rc
= set_pinentry_retry(pwm
);
597 return GPG_ERR_INV_STATE
;
599 pwm
->cmd
= ASYNC_CMD_OPEN
;
601 return do_nb_command(pwm
, "OPEN %s%s%s%s %s",
602 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
603 (pwm
->opts
& OPT_LOCK_ON_OPEN
) ? "--lock " : "",
604 pwm
->tcp_conn
? "--pinentry=0 " : "",
607 return do_nb_command(pwm
, "OPEN %s%s%s %s",
608 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
609 (pwm
->opts
& OPT_LOCK_ON_OPEN
) ? "--lock " : "",
614 gpg_error_t
pwmd_save_async(pwm_t
*pwm
)
619 return GPG_ERR_INV_ARG
;
622 return GPG_ERR_INV_STATE
;
624 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
625 return GPG_ERR_ASS_NESTED_COMMANDS
;
627 if (pwm
->lastcmd
!= ASYNC_CMD_SAVE2
) {
628 gpg_error_t rc
= send_pinentry_options(pwm
);
633 rc
= get_custom_passphrase(pwm
, &p
);
635 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
643 pwm
->cmd
= ASYNC_CMD_SAVE
;
645 char *tmp
= pwmd_strdup_printf("%li", pwm
->iterations
);
647 gpg_error_t rc
= do_nb_command(pwm
, "SAVE %s%s--iterations=%s --cipher=%s",
648 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
649 pwm
->tcp_conn
? "--pinentry=0 " : "",
650 pwm
->iterations
!= -1 ? tmp
: "",
651 pwm
->cipher
? pwm
->cipher
: "", p
? p
: "");
653 gpg_error_t rc
= do_nb_command(pwm
, "SAVE %s--iterations=%s --cipher=%s",
654 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
655 pwm
->iterations
!= -1 ? tmp
: "",
656 pwm
->cipher
? pwm
->cipher
: "", p
? p
: "");
663 static gpg_error_t
parse_assuan_line(pwm_t
*pwm
)
669 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
672 if (line
[0] == 'O' && line
[1] == 'K' &&
673 (line
[2] == 0 || line
[2] == ' ')) {
674 pwm
->state
= ASYNC_DONE
;
676 else if (line
[0] == '#') {
678 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' ')) {
679 if (pwm
->status_func
) {
680 rc
= pwm
->status_func(pwm
->status_data
,
681 line
[1] == 0 ? line
+1 : line
+2);
684 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
685 (line
[3] == 0 || line
[3] == ' ')) {
688 pwm
->state
= ASYNC_DONE
;
692 return gpg_err_code(rc
);
695 gpg_error_t
pwmd_pending_line(pwm_t
*pwm
)
698 return GPG_ERR_INV_ARG
;
701 return GPG_ERR_INV_STATE
;
703 return assuan_pending_line(pwm
->ctx
) ? 0 : GPG_ERR_NO_DATA
;
706 static pwmd_async_t
reset_async(pwm_t
*pwm
, int done
)
708 pwm
->state
= ASYNC_INIT
;
709 pwm
->cmd
= pwm
->lastcmd
= ASYNC_CMD_NONE
;
712 if (pwm
->nb_fd
!= -1) {
717 if (pwm
->_password
) {
718 pwmd_free(pwm
->_password
);
719 pwm
->_password
= NULL
;
724 pwm
->tcp_conn
->rc
= 0;
726 if (done
&& pwm
->tcp_conn
) {
727 _free_ssh_conn(pwm
->tcp_conn
);
728 pwm
->tcp_conn
= NULL
;
736 * Used for processing status messages when not in an async command and for
737 * waiting for the result from pwmd_open_async() and pwmd_save_async().
739 static gpg_error_t
_pwmd_process(pwm_t
*pwm
)
743 struct timeval tv
= {0, 0};
747 FD_SET(pwm
->fd
, &fds
);
749 n
= pth_select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
751 n
= select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
755 return gpg_error_from_syserror();
758 if (FD_ISSET(pwm
->fd
, &fds
))
759 rc
= parse_assuan_line(pwm
);
762 while (!rc
&& assuan_pending_line(pwm
->ctx
))
763 rc
= parse_assuan_line(pwm
);
765 return gpg_err_code(rc
);
768 static void reset_handle(pwm_t
*h
)
773 _pinentry_disconnect(h
);
781 gpg_error_t
pwmd_disconnect(pwm_t
*pwm
)
784 return GPG_ERR_INV_ARG
;
787 if (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1)
791 return GPG_ERR_INV_STATE
;
797 _ssh_disconnect(pwm
);
804 pwmd_async_t
pwmd_process(pwm_t
*pwm
, gpg_error_t
*rc
, char **result
)
806 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
809 struct timeval tv
= {0, 0};
816 return GPG_ERR_INV_ARG
;
821 *rc
= GPG_ERR_INV_ARG
;
824 else if (!pwm
->ctx
) {
827 *rc
= GPG_ERR_INV_STATE
;
831 case ASYNC_CMD_CONNECT
:
832 case ASYNC_CMD_HOSTKEY
:
838 /* When not in a command, this will let libassuan process status messages
839 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
840 * descriptor returned by pwmd_get_fd() to determine when this should be
841 * called or call pwmd_pending_line() to determine whether a buffered line
842 * needs to be processed. */
843 if (pwm
->cmd
== ASYNC_CMD_NONE
) {
844 *rc
= _pwmd_process(pwm
);
848 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
849 if (pwm
->state
== ASYNC_DONE
) {
850 *rc
= _pwmd_process(pwm
);
851 return reset_async(pwm
, 0);
854 if (pwm
->state
!= ASYNC_PROCESS
) {
855 *rc
= GPG_ERR_INV_STATE
;
860 if (pwm
->cmd
== ASYNC_CMD_DNS
) {
863 if (pwm
->tcp_conn
->rc
) {
864 *rc
= pwm
->tcp_conn
->rc
;
865 return reset_async(pwm
, 1);
870 n
= ares_fds(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
872 /* Shouldn't happen. */
877 n
= pth_select(n
, &rfds
, &wfds
, NULL
, &tv
);
879 n
= select(n
, &rfds
, &wfds
, NULL
, &tv
);
883 *rc
= gpg_error_from_syserror();
884 return reset_async(pwm
, 1);
888 ares_process(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
892 else if (pwm
->cmd
== ASYNC_CMD_CONNECT
) {
893 if (pwm
->tcp_conn
->rc
== GPG_ERR_EINPROGRESS
) {
895 socklen_t len
= sizeof(int);
898 FD_SET(pwm
->tcp_conn
->fd
, &fds
);
900 n
= pth_select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
902 n
= select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
905 if (!n
|| !FD_ISSET(pwm
->tcp_conn
->fd
, &fds
))
908 *rc
= gpg_error_from_syserror();
909 return reset_async(pwm
, 1);
912 ret
= getsockopt(pwm
->tcp_conn
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
915 *rc
= ret
? gpg_error_from_syserror() : gpg_error_from_errno(n
);
916 return reset_async(pwm
, 1);
919 pwm
->tcp_conn
->state
= SSH_NONE
;
920 pwm
->tcp_conn
->rc
= 0;
921 *rc
= _setup_ssh_session(pwm
);
923 if (*rc
&& *rc
!= GPG_ERR_EAGAIN
)
924 return reset_async(pwm
, 1);
926 else if (pwm
->tcp_conn
->rc
) {
927 *rc
= pwm
->tcp_conn
->rc
;
928 return reset_async(pwm
, 1);
931 switch (pwm
->tcp_conn
->state
) {
933 *rc
= _setup_ssh_init(pwm
);
936 *rc
= _setup_ssh_authlist(pwm
);
939 *rc
= _setup_ssh_auth(pwm
);
942 *rc
= _setup_ssh_agent(pwm
);
945 *rc
= _setup_ssh_channel(pwm
);
948 *rc
= _setup_ssh_shell(pwm
);
954 if (*rc
== GPG_ERR_EAGAIN
) {
956 return ASYNC_PROCESS
;
960 switch (pwm
->tcp_conn
->cmd
) {
961 case ASYNC_CMD_HOSTKEY
:
962 *result
= pwmd_strdup(pwm
->tcp_conn
->hostkey
);
965 *rc
= GPG_ERR_ENOMEM
;
972 return reset_async(pwm
, *rc
? 1 : 0);
977 if (pwm
->cmd
== ASYNC_CMD_OPEN2
|| pwm
->cmd
== ASYNC_CMD_SAVE2
) {
980 if (pwm
->nb_fd
== -1) {
981 *rc
= GPG_ERR_INV_STATE
;
982 return reset_async(pwm
, 0);
986 FD_SET(pwm
->nb_fd
, &fds
);
987 FD_SET(pwm
->fd
, &fds
);
989 n
= pth_select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
991 n
= select(pwm
->nb_fd
+1, &fds
, NULL
, NULL
, &tv
);
994 *rc
= gpg_error_from_syserror();
995 return reset_async(pwm
, 0);
998 if (n
> 0 && FD_ISSET(pwm
->nb_fd
, &fds
)) {
1001 size_t len
= pth_read(pwm
->nb_fd
, &nb
, sizeof(nb
));
1003 size_t len
= read(pwm
->nb_fd
, &nb
, sizeof(nb
));
1005 waitpid(pwm
->nb_pid
, &status
, WNOHANG
);
1007 if (len
!= sizeof(nb
)) {
1008 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
1009 *rc
= gpg_error_from_syserror();
1010 return reset_async(pwm
, 0);
1016 return reset_async(pwm
, 0);
1018 /* Since the non-blocking pinentry returned a success, do a
1019 * non-blocking OPEN or SAVE. */
1020 pwmd_async_cmd_t c
= pwm
->cmd
;
1021 reset_async(pwm
, 0);
1022 pwm
->_password
= pwmd_strdup(nb
.password
);
1023 memset(&nb
, 0, sizeof(pwmd_nb_status_t
));
1026 if (!pwm
->_password
) {
1027 *rc
= GPG_ERR_ENOMEM
;
1028 return reset_async(pwm
, 0);
1031 if (c
== ASYNC_CMD_SAVE2
)
1032 *rc
= pwmd_save_async(pwm
);
1034 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
1037 reset_async(pwm
, 0);
1041 return ASYNC_PROCESS
;
1044 /* Fall through so status messages can be processed during the
1050 *rc
= GPG_ERR_INV_STATE
;
1051 return reset_async(pwm
, 0);
1054 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
1056 *rc
= _pwmd_process(pwm
);
1058 if (*rc
&& *rc
!= GPG_ERR_INV_PASSPHRASE
)
1059 return reset_async(pwm
, 0);
1061 if (pwm
->cmd
== ASYNC_CMD_OPEN
&&
1062 *rc
== GPG_ERR_INV_PASSPHRASE
&&
1064 (!pwm
->tcp_conn
|| (pwm
->tcp_conn
&& pwm
->lastcmd
== ASYNC_CMD_OPEN2
)) &&
1066 ++pwm
->pin_try
< pwm
->pinentry_tries
) {
1067 if (!get_custom_passphrase(pwm
, NULL
))
1070 #ifdef WITH_PINENTRY
1071 if (pwm
->_password
) {
1072 reset_async(pwm
, 0);
1073 pwm
->lastcmd
= ASYNC_CMD_OPEN2
;
1074 *rc
= pwmd_open_async2(pwm
, pwm
->filename
);
1078 reset_async(pwm
, 0);
1079 pwm
->lastcmd
= ASYNC_CMD_OPEN
;
1080 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
1081 #ifdef WITH_PINENTRY
1087 if (*rc
|| pwm
->state
== ASYNC_DONE
)
1088 return reset_async(pwm
, 0);
1093 gpg_error_t
_assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
1094 char **result
, const char *cmd
)
1100 return GPG_ERR_INV_ARG
;
1102 if (strlen(cmd
) >= ASSUAN_LINELENGTH
+1)
1103 return GPG_ERR_LINE_TOO_LONG
;
1107 rc
= assuan_transact(ctx
, cmd
, inquire_realloc_cb
, &data
,
1109 pwm
->pctx
== ctx
? pwm
->_inquire_func
: inquire_cb
,
1110 pwm
->pctx
== ctx
? pwm
->_inquire_data
: pwm
,
1114 pwm
->status_func
, pwm
->status_data
);
1118 pwmd_free(data
.buf
);
1124 inquire_realloc_cb(&data
, "", 1);
1127 pwmd_free(data
.buf
);
1128 rc
= GPG_ERR_INV_ARG
;
1131 *result
= (char *)data
.buf
;
1135 return gpg_err_code(rc
);
1138 gpg_error_t
pwmd_inquire(pwm_t
*pwm
, const char *cmd
, pwmd_inquire_cb_t fn
,
1141 if (!pwm
|| !cmd
|| !fn
)
1142 return GPG_ERR_INV_ARG
;
1145 return GPG_ERR_INV_STATE
;
1147 pwm
->inquire_func
= fn
;
1148 pwm
->inquire_data
= data
;
1149 pwm
->inquire_sent
= 0;
1150 return _assuan_command(pwm
, pwm
->ctx
, NULL
, cmd
);
1153 gpg_error_t
pwmd_command_ap(pwm_t
*pwm
, char **result
, const char *cmd
,
1161 return GPG_ERR_INV_ARG
;
1164 return GPG_ERR_INV_STATE
;
1167 * C99 allows the dst pointer to be null which will calculate the length
1168 * of the would-be result and return it.
1171 len
= vsnprintf(NULL
, 0, cmd
, ap
)+1;
1172 buf
= (char *)pwmd_malloc(len
);
1176 return GPG_ERR_ENOMEM
;
1179 len
= vsnprintf(buf
, len
, cmd
, ap2
);
1182 if (buf
[strlen(buf
)-1] == '\n')
1183 buf
[strlen(buf
)-1] = 0;
1185 if (buf
[strlen(buf
)-1] == '\r')
1186 buf
[strlen(buf
)-1] = 0;
1188 gpg_error_t rc
= _assuan_command(pwm
, pwm
->ctx
, result
, buf
);
1193 gpg_error_t
pwmd_command(pwm_t
*pwm
, char **result
, const char *cmd
, ...)
1198 return GPG_ERR_INV_ARG
;
1201 return GPG_ERR_INV_STATE
;
1207 gpg_error_t rc
= pwmd_command_ap(pwm
, result
, cmd
, ap
);
1212 static gpg_error_t
send_pinentry_options(pwm_t
*pwm
)
1216 if (pwm
->pinentry_path
) {
1217 rc
= pwmd_command(pwm
, NULL
, "SET PINENTRY_PATH=%s",
1218 pwm
->pinentry_path
);
1224 if (pwm
->pinentry_tty
) {
1225 rc
= pwmd_command(pwm
, NULL
, "SET TTYNAME=%s", pwm
->pinentry_tty
);
1231 if (pwm
->pinentry_term
) {
1232 rc
= pwmd_command(pwm
, NULL
, "SET TTYTYPE=%s", pwm
->pinentry_term
);
1238 if (pwm
->pinentry_display
) {
1239 rc
= pwmd_command(pwm
, NULL
, "SET DISPLAY=%s",
1240 pwm
->pinentry_display
);
1247 rc
= pwmd_command(pwm
, NULL
, "SET TITLE=%s", pwm
->title
);
1254 rc
= pwmd_command(pwm
, NULL
, "SET DESC=%s", pwm
->desc
);
1261 rc
= pwmd_command(pwm
, NULL
, "SET PROMPT=%s", pwm
->prompt
);
1268 rc
= pwmd_command(pwm
, NULL
, "SET LC_CTYPE=%s", pwm
->lcctype
);
1274 if (pwm
->lcmessages
) {
1275 rc
= pwmd_command(pwm
, NULL
, "SET LC_MESSAGES=%s", pwm
->lcmessages
);
1281 if (pwm
->pinentry_timeout
>= 0 && !pwm
->pin_try
) {
1282 rc
= pwmd_command(pwm
, NULL
, "SET PINENTRY_TIMEOUT=%i",
1283 pwm
->pinentry_timeout
);
1292 gpg_error_t
pwmd_socket_type(pwm_t
*pwm
, pwmd_socket_t
*result
)
1294 if (!pwm
|| !result
)
1295 return GPG_ERR_INV_ARG
;
1298 if ((pwm
->fd
== -1 && !pwm
->tcp_conn
) ||
1299 (pwm
->fd
== -1 && pwm
->tcp_conn
&& pwm
->tcp_conn
->fd
== -1))
1303 return GPG_ERR_INV_STATE
;
1306 *result
= pwm
->tcp_conn
? PWMD_SOCKET_SSH
: PWMD_SOCKET_LOCAL
;
1308 *result
= PWMD_SOCKET_LOCAL
;
1313 static gpg_error_t
set_pinentry_retry(pwm_t
*pwm
)
1317 if (pwm
->pin_try
== 1) {
1318 rc
= pwmd_command(pwm
, NULL
, "SET TITLE=%s",
1319 N_("Invalid passphrase, please try again."));
1324 rc
= pwmd_command(pwm
, NULL
, "SET PINENTRY_TIMEOUT=0");
1330 static gpg_error_t
get_custom_passphrase(pwm_t
*pwm
, char **result
)
1332 gpg_error_t rc
= GPG_ERR_NO_DATA
;
1337 if (pwm
->password
|| pwm
->passfunc
)
1341 if (pwm
->password
) {
1343 *result
= pwm
->password
;
1345 else if (pwm
->passfunc
)
1346 rc
= pwm
->passfunc(pwm
->passdata
, result
);
1351 static gpg_error_t
do_pwmd_open(pwm_t
*pwm
, const char *filename
, int nb
,
1354 char *result
= NULL
;
1355 char *password
= NULL
;
1357 int no_pinentry
= 0;
1359 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1362 if (!pwm
|| !filename
|| !*filename
)
1363 return GPG_ERR_INV_ARG
;
1366 return GPG_ERR_INV_STATE
;
1369 * Avoid calling pinentry if the password is cached on the server or if
1370 * this is a new file.
1372 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", filename
);
1374 if (rc
== GPG_ERR_ENOENT
)
1377 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1380 if (rc
== GPG_ERR_NOT_FOUND
) {
1381 rc
= get_custom_passphrase(pwm
, &password
);
1383 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
1385 else if (rc
== GPG_ERR_NO_DATA
)
1386 rc
= GPG_ERR_NOT_FOUND
;
1391 #ifdef WITH_PINENTRY
1392 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1393 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1397 rc
= _pinentry_open(pwm
, filename
, &password
, nb
);
1399 /* pwmd_process() should be called if using a non-blocking local
1401 if (rc
|| (!rc
&& nb
))
1407 reset_async(pwm
, 0);
1410 if (!local_pinentry
&& !pwm
->tcp_conn
&& !pwm
->pin_try
) {
1412 if (!local_pinentry
&& !pwm
->pin_try
) {
1414 rc
= send_pinentry_options(pwm
);
1420 rc
= pwmd_command(pwm
, NULL
, "OPEN %s%s%s%s %s",
1421 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
1422 (pwm
->opts
& OPT_LOCK_ON_OPEN
) ? "--lock " : "",
1423 no_pinentry
? "--pinentry=0 " : "",
1424 filename
, password
? password
: "");
1427 * Keep the user defined password set with pwmd_setopt(). The password may
1428 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1430 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1431 pwmd_free(password
);
1433 if (rc
== GPG_ERR_INV_PASSPHRASE
) {
1434 if (++pwm
->pin_try
< pwm
->pinentry_tries
) {
1435 if (!get_custom_passphrase(pwm
, NULL
))
1438 #ifdef WITH_PINENTRY
1440 if (pwm
->tcp_conn
&& !local_pinentry
)
1442 else if (local_pinentry
)
1443 rc
= _getpin(pwm
, &password
, PWMD_PINENTRY_OPEN_FAILED
);
1447 rc
= _getpin(pwm
, &password
, PWMD_PINENTRY_OPEN_FAILED
);
1457 rc
= set_pinentry_retry(pwm
);
1464 #ifdef WITH_PINENTRY
1465 else if (local_pinentry
)
1466 _pinentry_disconnect(pwm
);
1472 #ifdef WITH_PINENTRY
1473 else if (rc
&& local_pinentry
)
1474 _pinentry_disconnect(pwm
);
1479 pwmd_free(pwm
->filename
);
1481 pwm
->filename
= pwmd_strdup(filename
);
1487 gpg_error_t
pwmd_open2(pwm_t
*pwm
, const char *filename
)
1489 #ifndef WITH_PINENTRY
1490 return GPG_ERR_NOT_IMPLEMENTED
;
1492 return do_pwmd_open(pwm
, filename
, 0, 1);
1496 gpg_error_t
pwmd_open(pwm_t
*pwm
, const char *filename
)
1498 return do_pwmd_open(pwm
, filename
, 0, 0);
1501 gpg_error_t
pwmd_open_async2(pwm_t
*pwm
, const char *filename
)
1503 #ifndef WITH_PINENTRY
1504 return GPG_ERR_NOT_IMPLEMENTED
;
1506 if (!pwm
|| !filename
)
1507 return GPG_ERR_INV_ARG
;
1510 return GPG_ERR_INV_STATE
;
1512 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1513 return GPG_ERR_ASS_NESTED_COMMANDS
;
1515 /* Initialize a new command since this is not a pinentry retry. */
1516 if (pwm
->lastcmd
!= ASYNC_CMD_OPEN2
)
1519 pwm
->cmd
= ASYNC_CMD_OPEN2
;
1520 pwm
->state
= ASYNC_PROCESS
;
1521 gpg_error_t rc
= do_pwmd_open(pwm
, filename
, 1, 1);
1524 reset_async(pwm
, 0);
1530 struct open_inquire_s
{
1533 pwmd_inquire_cb_t func
;
1538 /* We need to send the filename argument here rather than confusing the app.
1539 * The app will only send the passphrase and nothing else.
1541 static gpg_error_t
open_inquire_cb(void *user
, const char *cmd
,
1542 gpg_error_t rc
, char **data
, size_t *len
)
1544 struct open_inquire_s
*o
= user
;
1550 char *line
= pwmd_strdup_printf("%s ", o
->filename
);
1551 rc
= assuan_send_data(o
->pwm
->ctx
, line
, strlen(line
));
1555 /* Give the user a chance to cleanup. */
1557 return o
->func(o
->user
, cmd
, rc
, data
, len
);
1562 return o
->func(o
->user
, cmd
, rc
, data
, len
);
1565 gpg_error_t
pwmd_open_inquire(pwm_t
*pwm
, const char *filename
,
1566 pwmd_inquire_cb_t func
, void *user
)
1568 if (!pwm
|| !filename
|| !func
)
1569 return GPG_ERR_INV_ARG
;
1572 return GPG_ERR_INV_STATE
;
1574 struct open_inquire_s
*inq
= pwmd_calloc(1, sizeof(struct open_inquire_s
));
1578 return GPG_ERR_ENOMEM
;
1581 inq
->filename
= pwmd_strdup(filename
);
1585 char *cmd
= pwmd_strdup_printf("OPEN --inquire %s%s",
1586 (pwm
->opts
& OPT_LOCK_ON_OPEN
) ? "--lock " : "",
1587 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "");
1589 rc
= pwmd_inquire(pwm
, cmd
, open_inquire_cb
, inq
);
1591 pwmd_free(inq
->filename
);
1596 pwmd_free(pwm
->filename
);
1598 pwm
->filename
= pwmd_strdup(filename
);
1600 if (!pwm
->filename
) {
1602 rc
= GPG_ERR_ENOMEM
;
1609 gpg_error_t
pwmd_save_inquire(pwm_t
*pwm
, pwmd_inquire_cb_t func
, void *user
)
1612 return GPG_ERR_INV_ARG
;
1615 return GPG_ERR_INV_STATE
;
1618 char *tmp
= pwmd_strdup_printf("%li", pwm
->iterations
);
1619 char *cmd
= pwmd_strdup_printf("SAVE %s --inquire --iterations=%s --cipher=%s",
1620 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
1621 pwm
->iterations
!= -1 ? tmp
: "",
1622 pwm
->cipher
? pwm
->cipher
: "");
1624 rc
= pwmd_inquire(pwm
, cmd
, func
, user
);
1629 static gpg_error_t
do_pwmd_save(pwm_t
*pwm
, int nb
, int local_pinentry
)
1631 char *result
= NULL
;
1632 char *password
= NULL
;
1636 return GPG_ERR_INV_ARG
;
1639 return GPG_ERR_INV_STATE
;
1641 rc
= pwmd_command(pwm
, &result
, "ISCACHED %s", pwm
->filename
);
1643 if (rc
== GPG_ERR_ENOENT
)
1644 rc
= GPG_ERR_NOT_FOUND
;
1646 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
)
1649 if (rc
== GPG_ERR_NOT_FOUND
) {
1650 rc
= get_custom_passphrase(pwm
, &password
);
1652 if (rc
&& rc
!= GPG_ERR_NO_DATA
)
1654 else if (rc
== GPG_ERR_NO_DATA
)
1655 rc
= GPG_ERR_NOT_FOUND
;
1660 if (rc
== GPG_ERR_NOT_FOUND
&& local_pinentry
) {
1661 #ifdef WITH_PINENTRY
1662 /* Get the password using the LOCAL pinentry. */
1666 pwmd_nb_status_t pw
;
1669 return gpg_error_from_syserror();
1682 pw
.error
= _do_save_getpin(pwm
, &password
);
1685 snprintf(pw
.password
, sizeof(pw
.password
), "%s",
1687 pwmd_free(password
);
1690 pth_write(p
[1], &pw
, sizeof(pw
));
1692 write(p
[1], &pw
, sizeof(pw
));
1694 memset(&pw
, 0, sizeof(pw
));
1699 rc
= gpg_error_from_syserror();
1713 rc
= _do_save_getpin(pwm
, &password
);
1720 pwm
->state
= ASYNC_DONE
;
1723 reset_async(pwm
, 0);
1726 if (!local_pinentry
&& !pwm
->tcp_conn
) {
1728 if (!local_pinentry
) {
1730 rc
= send_pinentry_options(pwm
);
1736 char *tmp
= pwmd_strdup_printf("%li", pwm
->iterations
);
1739 rc
= pwmd_command(pwm
, NULL
, "SAVE %s%s--iterations=%s --cipher=%s %s",
1740 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
1741 local_pinentry
|| pwm
->tcp_conn
? "--pinentry=0 " : "",
1742 pwm
->iterations
!= -1 ? tmp
: "",
1743 pwm
->cipher
? pwm
->cipher
: "",
1744 password
? password
: "");
1746 rc
= pwmd_command(pwm
, NULL
, "SAVE %s--iterations=%s --cipher=%s %s",
1747 (pwm
->opts
& OPT_BASE64
) ? "--base64 " : "",
1748 pwm
->iterations
!= -1 ? tmp
: "",
1749 pwm
->cipher
? pwm
->cipher
: "",
1750 password
? password
: "");
1755 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1756 pwmd_free(password
);
1761 gpg_error_t
pwmd_save_async2(pwm_t
*pwm
)
1763 #ifndef WITH_PINENTRY
1764 return GPG_ERR_NOT_IMPLEMENTED
;
1767 return GPG_ERR_INV_ARG
;
1770 return GPG_ERR_INV_STATE
;
1772 if (pwm
->cmd
!= ASYNC_CMD_NONE
)
1773 return GPG_ERR_ASS_NESTED_COMMANDS
;
1775 pwm
->cmd
= ASYNC_CMD_SAVE2
;
1776 pwm
->state
= ASYNC_PROCESS
;
1777 gpg_error_t rc
= do_pwmd_save(pwm
, 1, 1);
1780 reset_async(pwm
, 0);
1786 gpg_error_t
pwmd_save2(pwm_t
*pwm
)
1788 #ifndef WITH_PINENTRY
1789 return GPG_ERR_NOT_IMPLEMENTED
;
1791 return do_pwmd_save(pwm
, 0, 1);
1795 gpg_error_t
pwmd_save(pwm_t
*pwm
)
1797 return do_pwmd_save(pwm
, 0, 0);
1800 gpg_error_t
pwmd_setopt(pwm_t
*pwm
, pwmd_option_t opt
, ...)
1808 return GPG_ERR_INV_ARG
;
1813 case PWMD_OPTION_BASE64
:
1814 n
= va_arg(ap
, int);
1816 if (n
< 0 || n
> 1) {
1817 rc
= GPG_ERR_INV_VALUE
;
1822 pwm
->opts
|= OPT_BASE64
;
1824 pwm
->opts
&= ~OPT_BASE64
;
1827 case PWMD_OPTION_ITERATIONS
:
1828 pwm
->iterations
= va_arg(ap
, long);
1830 if (pwm
->iterations
< -1) {
1831 pwm
->iterations
= -1;
1832 rc
= GPG_ERR_INV_VALUE
;
1836 case PWMD_OPTION_CIPHER
:
1837 arg1
= va_arg(ap
, char *);
1840 pwmd_free(pwm
->cipher
);
1842 pwm
->cipher
= arg1
? pwmd_strdup(arg1
) : NULL
;
1844 case PWMD_OPTION_LOCK_ON_OPEN
:
1845 n
= va_arg(ap
, int);
1848 rc
= GPG_ERR_INV_VALUE
;
1851 pwm
->opts
|= OPT_LOCK_ON_OPEN
;
1853 pwm
->opts
&= ~OPT_LOCK_ON_OPEN
;
1856 case PWMD_OPTION_INQUIRE_TOTAL
:
1857 pwm
->inquire_total
= va_arg(ap
, size_t);
1859 case PWMD_OPTION_STATUS_CB
:
1860 pwm
->status_func
= va_arg(ap
, pwmd_status_cb_t
);
1862 case PWMD_OPTION_STATUS_DATA
:
1863 pwm
->status_data
= va_arg(ap
, void *);
1865 case PWMD_OPTION_PASSPHRASE_CB
:
1866 pwm
->passfunc
= va_arg(ap
, pwmd_passphrase_cb_t
);
1868 case PWMD_OPTION_PASSPHRASE_DATA
:
1869 pwm
->passdata
= va_arg(ap
, void *);
1871 case PWMD_OPTION_PASSPHRASE
:
1872 arg1
= va_arg(ap
, char *);
1875 pwmd_free(pwm
->password
);
1877 pwm
->password
= arg1
? pwmd_strdup(arg1
) : NULL
;
1879 case PWMD_OPTION_PINENTRY_TRIES
:
1880 n
= va_arg(ap
, int);
1883 rc
= GPG_ERR_INV_VALUE
;
1885 pwm
->pinentry_tries
= n
;
1888 case PWMD_OPTION_PINENTRY_TIMEOUT
:
1889 n
= va_arg(ap
, int);
1892 rc
= GPG_ERR_INV_VALUE
;
1894 pwm
->pinentry_timeout
= n
;
1897 case PWMD_OPTION_PINENTRY_PATH
:
1898 if (pwm
->pinentry_path
)
1899 pwmd_free(pwm
->pinentry_path
);
1901 pwm
->pinentry_path
= _expand_homedir(va_arg(ap
, char *), NULL
);
1903 case PWMD_OPTION_PINENTRY_TTY
:
1904 arg1
= va_arg(ap
, char *);
1906 if (pwm
->pinentry_tty
)
1907 pwmd_free(pwm
->pinentry_tty
);
1909 pwm
->pinentry_tty
= arg1
? pwmd_strdup(arg1
) : NULL
;
1911 case PWMD_OPTION_PINENTRY_DISPLAY
:
1912 if (pwm
->pinentry_display
)
1913 pwmd_free(pwm
->pinentry_display
);
1915 pwm
->pinentry_display
= pwmd_strdup(va_arg(ap
, char *));
1917 case PWMD_OPTION_PINENTRY_TERM
:
1918 arg1
= va_arg(ap
, char *);
1920 if (pwm
->pinentry_term
)
1921 pwmd_free(pwm
->pinentry_term
);
1923 pwm
->pinentry_term
= arg1
? pwmd_strdup(arg1
) : NULL
;
1925 case PWMD_OPTION_PINENTRY_TITLE
:
1927 pwmd_free(pwm
->title
);
1929 pwm
->title
= _percent_escape(va_arg(ap
, char *));
1931 case PWMD_OPTION_PINENTRY_PROMPT
:
1933 pwmd_free(pwm
->prompt
);
1935 pwm
->prompt
= _percent_escape(va_arg(ap
, char *));
1937 case PWMD_OPTION_PINENTRY_DESC
:
1939 pwmd_free(pwm
->desc
);
1941 pwm
->desc
= _percent_escape(va_arg(ap
, char *));
1943 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
1944 arg1
= va_arg(ap
, char *);
1947 pwmd_free(pwm
->lcctype
);
1949 pwm
->lcctype
= arg1
? pwmd_strdup(arg1
) : NULL
;
1951 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
1952 arg1
= va_arg(ap
, char *);
1954 if (pwm
->lcmessages
)
1955 pwmd_free(pwm
->lcmessages
);
1957 pwm
->lcmessages
= arg1
? pwmd_strdup(arg1
) : NULL
;
1960 case PWMD_OPTION_IP_VERSION
:
1961 n
= va_arg(ap
, int);
1970 rc
= GPG_ERR_INV_VALUE
;
1974 case PWMD_OPTION_KNOWNHOST_CB
:
1975 pwm
->kh_cb
= va_arg(ap
, pwmd_knownhost_cb_t
);
1977 case PWMD_OPTION_KNOWNHOST_DATA
:
1978 pwm
->kh_data
= va_arg(ap
, void *);
1980 case PWMD_OPTION_SSH_AGENT
:
1981 pwm
->use_agent
= va_arg(ap
, int);
1983 if (pwm
->use_agent
< 0 || pwm
->use_agent
> 1) {
1985 rc
= GPG_ERR_INV_VALUE
;
1990 case PWMD_OPTION_IP_VERSION
:
1991 case PWMD_OPTION_KNOWNHOST_CB
:
1992 case PWMD_OPTION_KNOWNHOST_DATA
:
1993 case PWMD_OPTION_SSH_AGENT
:
1994 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1998 rc
= GPG_ERR_UNKNOWN_OPTION
;
2006 gpg_error_t
pwmd_get_fds(pwm_t
*pwm
, pwmd_fd_t
*fds
, int *n_fds
)
2011 int afds
[ARES_GETSOCK_MAXNUM
];
2016 if (!pwm
|| !fds
|| !n_fds
|| *n_fds
<= 0)
2017 return GPG_ERR_INV_ARG
;
2021 memset(afds
, 0, sizeof(int)*ARES_GETSOCK_MAXNUM
);
2023 memset(fds
, 0, sizeof(pwmd_fd_t
)*in_total
);
2028 case ASYNC_CMD_NONE
:
2029 case ASYNC_CMD_OPEN
:
2030 case ASYNC_CMD_SAVE
:
2031 #ifdef WITH_PINENTRY
2035 return GPG_ERR_INV_STATE
;
2038 fds
[fd
].fd
= pwm
->fd
;
2039 fds
[fd
++].flags
= PWMD_FD_READABLE
;
2041 #ifdef WITH_PINENTRY
2042 case ASYNC_CMD_OPEN2
:
2043 case ASYNC_CMD_SAVE2
:
2044 /* The command has already completed (cached or new). */
2045 if (pwm
->state
== ASYNC_DONE
)
2048 if (pwm
->nb_fd
== -1)
2049 return GPG_ERR_INV_STATE
;
2052 fds
[fd
].fd
= pwm
->nb_fd
;
2053 fds
[fd
++].flags
= PWMD_FD_READABLE
;
2058 if (!pwm
->tcp_conn
|| !pwm
->tcp_conn
->chan
)
2059 return GPG_ERR_INV_STATE
;
2061 n
= ares_getsock(pwm
->tcp_conn
->chan
, afds
, ARES_GETSOCK_MAXNUM
);
2063 for (i
= 0; i
< ARES_GETSOCK_MAXNUM
; i
++) {
2066 if (fd
> in_total
) {
2068 return GPG_ERR_ERANGE
;
2071 if (ARES_GETSOCK_READABLE(n
, i
)) {
2073 fds
[fd
].flags
|= PWMD_FD_READABLE
;
2076 if (ARES_GETSOCK_WRITABLE(n
, i
)) {
2078 fds
[fd
].flags
|= PWMD_FD_WRITABLE
;
2082 fds
[fd
++].fd
= afds
[i
];
2087 case ASYNC_CMD_CONNECT
:
2088 case ASYNC_CMD_HOSTKEY
:
2089 if (!pwm
->tcp_conn
|| pwm
->tcp_conn
->fd
== -1)
2090 return GPG_ERR_INV_STATE
;
2093 fds
[fd
].fd
= pwm
->tcp_conn
->fd
;
2094 fds
[fd
++].flags
= PWMD_FD_READABLE
;
2099 return GPG_ERR_INV_STATE
;
2102 pwm_t
*pwmd_new(const char *name
)
2104 pwm_t
*h
= pwmd_calloc(1, sizeof(pwm_t
));
2110 h
->name
= pwmd_strdup(name
);
2119 h
->pinentry_timeout
= -30;
2120 h
->pinentry_tries
= 3;
2123 h
->prot
= PWMD_IP_ANY
;
2126 if (ttyname(STDOUT_FILENO
)) {
2129 ttyname_r(STDOUT_FILENO
, buf
, sizeof(buf
));
2130 h
->pinentry_tty
= pwmd_strdup(buf
);
2132 if (!h
->pinentry_tty
)
2136 if (getenv("TERM") && h
->pinentry_tty
) {
2137 h
->pinentry_term
= pwmd_strdup(getenv("TERM"));
2139 if (!h
->pinentry_term
)
2143 if (getenv("DISPLAY")) {
2144 h
->pinentry_display
= pwmd_strdup(getenv("DISPLAY"));
2146 if (!h
->pinentry_display
)
2157 void pwmd_free(void *ptr
)
2162 void *pwmd_malloc(size_t size
)
2164 return _xmalloc(size
);
2167 void *pwmd_calloc(size_t nmemb
, size_t size
)
2169 return _xcalloc(nmemb
, size
);
2172 void *pwmd_realloc(void *ptr
, size_t size
)
2174 return _xrealloc(ptr
, size
);
2177 char *pwmd_strdup(const char *str
)
2179 return _xstrdup(str
);
2182 char *pwmd_strdup_printf(const char *fmt
, ...)
2193 len
= vsnprintf(NULL
, 0, fmt
, ap
);
2195 buf
= pwmd_malloc(++len
);
2198 vsnprintf(buf
, len
, fmt
, ap2
);
2204 gpg_error_t
pwmd_getpin(pwm_t
*pwm
, const char *filename
, char **result
,
2205 pwmd_pinentry_t which
)
2207 #ifndef WITH_PINENTRY
2208 return GPG_ERR_NOT_IMPLEMENTED
;
2210 return _pwmd_getpin(pwm
, filename
, result
, which
);
2214 const char *pwmd_version()
2216 return LIBPWMD_VERSION_STR
;