2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
31 #include <sys/types.h>
32 #include <sys/socket.h>
42 #include <sys/select.h>
62 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
63 #include <sys/types.h>
64 #include <sys/socket.h>
66 #include <netinet/in.h>
69 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
79 hook_read (assuan_context_t ctx
, assuan_fd_t fd
, void *data
, size_t len
)
81 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
82 pwm_t
*pwm
= assuan_get_pointer (ctx
);
85 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->ssh
)
86 return read_hook_ssh (pwm
->tcp
->ssh
, fd
, data
, len
);
89 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->tls
)
90 return read_hook_tls (pwm
->tcp
->tls
, fd
, data
, len
);
94 return read ((int) fd
, data
, len
);
98 hook_write (assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
102 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
103 pwm_t
*pwm
= assuan_get_pointer (ctx
);
106 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->ssh
)
107 return write_hook_ssh (pwm
->tcp
->ssh
, fd
, data
, len
);
110 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->tls
)
111 return write_hook_tls (pwm
->tcp
->tls
, fd
, data
, len
);
115 /* libassuan cannot handle EAGAIN when doing writes. */
118 wrote
= write ((int) fd
, data
, len
);
119 if (wrote
== -1 && errno
== EAGAIN
)
122 while (wrote
== -1 && errno
== EAGAIN
);
128 hook_waitpid (assuan_context_t ctx
, pid_t pid
, int action
, int *status
,
131 return waitpid (pid
, status
, options
);
137 static int initialized
;
140 // May be called more than once.
141 gnutls_global_init ();
151 bindtextdomain ("libpwmd", LOCALEDIR
);
165 gnutls_global_deinit ();
170 _connect_finalize (pwm_t
* pwm
)
174 int n
= assuan_get_active_fds (pwm
->ctx
, 0, active
, N_ARRAY (active
));
177 return GPG_ERR_EBADFD
;
181 pwm
->pinentry_pid
= -1;
185 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION NAME=%s",
192 connect_uds (pwm_t
* pwm
, const char *path
)
194 char *socketpath
= NULL
;
200 return GPG_ERR_INV_ARG
;
202 pwbuf
= _getpwuid (&pw
);
204 return gpg_error_from_syserror ();
207 socketpath
= pwmd_strdup_printf ("%s/.pwmd/socket", pw
.pw_dir
);
209 socketpath
= _expand_homedir ((char *) path
, &pw
);
213 return GPG_ERR_ENOMEM
;
215 rc
= assuan_socket_connect (pwm
->ctx
, socketpath
, ASSUAN_INVALID_FD
, 0);
216 pwmd_free (socketpath
);
217 return rc
? rc
: _connect_finalize (pwm
);
221 init_handle (pwm_t
* pwm
)
224 static struct assuan_malloc_hooks mhooks
= {
225 pwmd_malloc
, pwmd_realloc
, pwmd_free
227 static struct assuan_system_hooks shooks
= {
228 ASSUAN_SYSTEM_HOOKS_VERSION
,
236 NULL
, //sendmsg both are used for FD passing
244 rc
= assuan_new_ext (&pwm
->ctx
, GPG_ERR_SOURCE_DEFAULT
, &mhooks
, NULL
,
249 assuan_set_pointer (pwm
->ctx
, pwm
);
250 assuan_ctx_set_system_hooks (pwm
->ctx
, &shooks
);
254 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
256 free_tcp (struct tcp_s
*tcp
)
262 _free_ssh_conn (tcp
->ssh
);
268 pwmd_free (tcp
->host
);
271 freeaddrinfo (tcp
->addrs
);
279 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
281 tcp_connect_common (pwm_t
* pwm
)
283 struct addrinfo hints
= { 0 };
291 hints
.ai_family
= AF_UNSPEC
;
294 hints
.ai_family
= AF_INET
;
297 hints
.ai_family
= AF_INET6
;
301 hints
.ai_socktype
= SOCK_STREAM
;
302 snprintf (portstr
, sizeof (portstr
), "%i", pwm
->tcp
->port
);
303 n
= getaddrinfo (pwm
->tcp
->host
, portstr
, &hints
, &pwm
->tcp
->addrs
);
306 fprintf (stderr
, "%s\n", gai_strerror (n
));
307 return GPG_ERR_UNKNOWN_HOST
; //FIXME
310 for (pwm
->tcp
->addr
= pwm
->tcp
->addrs
; pwm
->tcp
->addr
;
311 pwm
->tcp
->addr
= pwm
->tcp
->addrs
->ai_next
)
313 pwm
->fd
= socket (pwm
->tcp
->addr
->ai_family
, SOCK_STREAM
, 0);
316 rc
= gpg_error_from_syserror ();
317 if (pwm
->tcp
->addr
== pwm
->tcp
->addrs
->ai_next
)
322 if (pwm
->socket_timeout
)
323 fcntl (pwm
->fd
, F_SETFL
, O_NONBLOCK
);
325 if (connect (pwm
->fd
, pwm
->tcp
->addr
->ai_addr
,
326 pwm
->tcp
->addr
->ai_family
== AF_INET6
327 ? sizeof (struct sockaddr_in6
)
328 : sizeof (struct sockaddr
)) == -1)
331 struct timeval tv
= { pwm
->socket_timeout
, 0 };
334 rc
= gpg_error_from_syserror ();
335 if (gpg_err_code (rc
) != GPG_ERR_EINPROGRESS
)
339 if (pwm
->tcp
->addr
== pwm
->tcp
->addrs
->ai_next
)
344 FD_SET (pwm
->fd
, &wfds
);
345 n
= select (pwm
->fd
+1, NULL
, &wfds
, NULL
, &tv
);
348 rc
= gpg_error (GPG_ERR_ETIMEDOUT
);
353 getsockopt (pwm
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
355 rc
= gpg_error_from_errno (n
);
358 rc
= gpg_error_from_syserror ();
364 if (pwm
->tcp
->addr
== pwm
->tcp
->addrs
->ai_next
365 || gpg_err_code (rc
) == GPG_ERR_ETIMEDOUT
)
375 if (!rc
&& pwm
->socket_timeout
)
376 fcntl (pwm
->fd
, F_SETFL
, 0);
383 pwmd_connect (pwm_t
* pwm
, const char *url
, ...)
389 return FINISH (GPG_ERR_INV_ARG
);
392 rc
= init_handle (pwm
);
397 rc
= GPG_ERR_UNSUPPORTED_PROTOCOL
;
400 rc
= connect_uds (pwm
, p
);
401 else if (!p
|| !strncmp (p
, "file://", 7))
405 rc
= connect_uds (pwm
, p
);
407 else if (!strncmp (p
, "ssh://", 6) || !strncmp (p
, "ssh6://", 7) ||
408 !strncmp (p
, "ssh4://", 7))
411 return FINISH (GPG_ERR_NOT_IMPLEMENTED
);
415 char *username
= NULL
;
417 if (!strncmp (p
, "ssh6://", 7))
419 pwm
->prot
= PWMD_IPV6
;
422 else if (!strncmp (p
, "ssh4://", 7))
424 pwm
->prot
= PWMD_IPV4
;
429 pwm
->prot
= PWMD_IP_ANY
;
433 rc
= _parse_ssh_url (p
, &host
, &port
, &username
);
437 char *identity
= NULL
;
438 char *knownhosts
= NULL
;
441 identity
= va_arg (ap
, char *);
443 if (!identity
&& !pwm
->use_agent
)
444 rc
= GPG_ERR_INV_ARG
;
446 knownhosts
= va_arg (ap
, char *);
451 rc
= _do_ssh_connect (pwm
, host
, port
, identity
, username
,
455 rc
= _connect_finalize (pwm
);
465 pwmd_free (username
);
469 else if (!strncmp (p
, "tls://", 6) || !strncmp (p
, "tls6://", 7) ||
470 !strncmp (p
, "tls4://", 7))
473 return FINISH (GPG_ERR_NOT_IMPLEMENTED
);
478 if (!strncmp (p
, "tls6://", 7))
480 pwm
->prot
= PWMD_IPV6
;
483 else if (!strncmp (p
, "tls4://", 7))
485 pwm
->prot
= PWMD_IPV4
;
490 pwm
->prot
= PWMD_IP_ANY
;
494 rc
= _parse_tls_url (p
, &host
, &port
);
498 char *clientcert
= NULL
;
499 char *clientkey
= NULL
;
502 char *server_fp
= NULL
;
505 clientcert
= va_arg (ap
, char *);
508 rc
= GPG_ERR_INV_ARG
;
511 clientkey
= va_arg (ap
, char *);
513 rc
= GPG_ERR_INV_ARG
;
516 cacert
= va_arg (ap
, char *);
518 rc
= GPG_ERR_INV_ARG
;
521 prio
= va_arg (ap
, char *);
522 server_fp
= va_arg (ap
, char *);
530 rc
= _do_tls_connect (pwm
, host
, port
, clientcert
, clientkey
,
531 cacert
, prio
, server_fp
, pwm
->tls_verify
);
534 rc
= _connect_finalize (pwm
);
552 disconnect (pwm_t
* pwm
)
558 assuan_release (pwm
->ctx
);
560 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
569 pwmd_close (pwm_t
* pwm
)
575 pwmd_free (pwm
->pinentry_error
);
576 pwmd_free (pwm
->pinentry_desc
);
577 pwmd_free (pwm
->pinentry_prompt
);
578 pwmd_free (pwm
->pinentry_tty
);
579 pwmd_free (pwm
->pinentry_display
);
580 pwmd_free (pwm
->pinentry_term
);
581 pwmd_free (pwm
->pinentry_lcctype
);
582 pwmd_free (pwm
->pinentry_lcmessages
);
583 pwmd_free (pwm
->filename
);
584 pwmd_free (pwm
->name
);
588 _pinentry_disconnect (pwm
);
595 inquire_realloc_cb (void *data
, const void *buffer
, size_t len
)
597 membuf_t
*mem
= (membuf_t
*) data
;
603 if ((p
= pwmd_realloc (mem
->buf
, mem
->len
+ len
)) == NULL
)
604 return gpg_error (GPG_ERR_ENOMEM
);
607 memcpy ((char *) mem
->buf
+ mem
->len
, buffer
, len
);
613 get_password (pwm_t
* pwm
, char **result
, size_t * len
,
614 pwmd_pinentry_t w
, int echo
)
616 char buf
[LINE_MAX
] = { 0 }, *p
;
617 struct termios told
, tnew
;
626 if (!isatty (STDIN_FILENO
))
628 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
629 return GPG_ERR_ENOTTY
;
634 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
635 return gpg_error_from_syserror ();
637 memcpy (&tnew
, &told
, sizeof (struct termios
));
638 tnew
.c_lflag
&= ~(ECHO
);
639 tnew
.c_lflag
|= ICANON
| ECHONL
;
641 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
645 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
646 return gpg_error_from_errno (n
);
652 case PWMD_PINENTRY_OPEN
:
653 fprintf (stderr
, N_("Password for %s: "), pwm
->filename
);
655 case PWMD_PINENTRY_OPEN_FAILED
:
656 fprintf (stderr
, N_("Invalid password. Password for %s: "),
659 case PWMD_PINENTRY_SAVE
:
660 fprintf (stderr
, N_("New password for %s: "), pwm
->filename
);
662 case PWMD_PINENTRY_SAVE_CONFIRM
:
663 fprintf (stderr
, N_("Confirm password: "));
669 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
671 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
676 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
681 return GPG_ERR_CANCELED
;
684 /* Strip the newline character. */
685 p
[strlen (p
) - 1] = 0;
689 key
= pwmd_strdup_printf ("%s", p
);
690 memset (buf
, 0, sizeof (buf
));
692 return GPG_ERR_ENOMEM
;
703 *result
= pwmd_strdup ("");
713 pwmd_password (pwm_t
* pwm
, const char *keyword
, char **data
, size_t * size
)
716 int new_password
= 0;
717 char *password
= NULL
, *newpass
= NULL
;
726 if (!strcmp (keyword
, "NEW_PASSPHRASE"))
729 if (!new_password
&& pwm
->pinentry_try
)
733 if (pwm
->disable_pinentry
)
735 rc
= get_password (pwm
, &password
, size
,
736 new_password
? PWMD_PINENTRY_SAVE
:
737 error
? PWMD_PINENTRY_OPEN_FAILED
:
738 PWMD_PINENTRY_OPEN
, 0);
739 if (!rc
&& new_password
)
740 rc
= get_password (pwm
, &newpass
, size
, PWMD_PINENTRY_SAVE_CONFIRM
,
745 pwmd_pinentry_t which
;
749 ? PWMD_PINENTRY_SAVE_FAILED
: PWMD_PINENTRY_OPEN_FAILED
;
751 which
= new_password
? PWMD_PINENTRY_SAVE
: PWMD_PINENTRY_OPEN
;
753 rc
= pwmd_getpin (pwm
, pwm
->filename
, &password
, size
, which
);
754 if (!rc
&& new_password
)
755 rc
= pwmd_getpin (pwm
, pwm
->filename
, &newpass
, size
,
756 PWMD_PINENTRY_SAVE_CONFIRM
);
759 if (!rc
&& new_password
)
761 if ((!password
&& newpass
) || (!newpass
&& password
)
762 || strcmp (newpass
, password
))
764 if (pwm
->disable_pinentry
)
765 fprintf (stderr
, N_("Passphrases do not match.\n"));
767 pwmd_free (password
);
769 password
= newpass
= NULL
;
775 (void) pwmd_getpin (pwm
, pwm
->filename
, NULL
, NULL
, PWMD_PINENTRY_CLOSE
);
784 inquire_cb (void *data
, const char *keyword
)
786 pwm_t
*pwm
= (pwm_t
*) data
;
791 int new_password
= 0;
793 if (!strcmp (keyword
, "PASSPHRASE"))
795 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
798 /* Shouldn't get this far without a callback. */
799 if (!pwm
->override_inquire
&& !pwm
->inquire_func
800 && !is_password
&& !new_password
)
801 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB
);
810 if (!pwm
->override_inquire
&& (is_password
|| new_password
))
813 rc
= pwmd_password (data
, keyword
, &result
, &len
);
818 rc
= pwm
->inquire_func (pwm
->inquire_data
, keyword
, rc
, &result
,
822 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
824 #ifndef LIBASSUAN_2_1_0
825 gpg_error_t trc
= rc
;
827 /* Cancel this inquire. */
828 rc
= assuan_send_data (pwm
->ctx
, NULL
, 1);
834 /* There is a bug (or feature?) in assuan_send_data() that
835 * when cancelling an inquire the next read from the server is
836 * not done until the next command making the next command
837 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
839 rc
= assuan_read_line (pwm
->ctx
, &line
, &len
);
841 /* Restore the original error. This differs from the error
842 * returned from the pwmd command (GPG_ERR_CANCELED). This
843 * error is returned to the calling function.
852 if (gpg_err_code (rc
) == GPG_ERR_EOF
|| !rc
)
854 if (len
<= 0 && !result
)
859 else if ((len
<= 0 && result
) || (len
&& !result
))
861 rc
= gpg_error (GPG_ERR_INV_ARG
);
865 if (pwm
->inquire_maxlen
866 && pwm
->inquire_sent
+ len
> pwm
->inquire_maxlen
)
868 rc
= gpg_error (GPG_ERR_TOO_LARGE
);
870 rc
= pwm
->inquire_func (pwm
->inquire_data
, keyword
, rc
,
875 arc
= assuan_send_data (pwm
->ctx
, result
, len
);
876 if (gpg_err_code (rc
) == GPG_ERR_EOF
)
889 pwm
->inquire_sent
+= len
;
891 if (pwm
->status_func
)
893 char buf
[ASSUAN_LINELENGTH
];
895 snprintf (buf
, sizeof (buf
), "XFER %lu %lu", pwm
->inquire_sent
,
897 rc
= pwm
->status_func (pwm
->status_data
, buf
);
911 parse_assuan_line (pwm_t
* pwm
)
917 rc
= assuan_read_line (pwm
->ctx
, &line
, &len
);
920 if (line
[0] == 'O' && line
[1] == 'K' &&
921 (line
[2] == 0 || line
[2] == ' '))
924 else if (line
[0] == '#')
927 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' '))
929 if (pwm
->status_func
)
931 rc
= pwm
->status_func (pwm
->status_data
,
932 line
[1] == 0 ? line
+ 1 : line
+ 2);
935 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
936 (line
[3] == 0 || line
[3] == ' '))
939 rc
= strtol (line
, NULL
, 10);
947 reset_handle_state (pwm_t
* pwm
, int done
)
949 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
962 reset_handle (pwm_t
* h
)
967 _pinentry_disconnect (h
);
969 reset_handle_state (h
, 0);
973 pwmd_disconnect (pwm_t
* pwm
)
976 return FINISH (GPG_ERR_INV_ARG
);
979 return FINISH (GPG_ERR_INV_STATE
);
986 /* Note that this should only be called when not in a command. */
988 pwmd_process (pwm_t
* pwm
)
992 struct timeval tv
= { 0, 0 };
996 return FINISH (GPG_ERR_INV_ARG
);
998 return FINISH (GPG_ERR_INV_STATE
);
1001 FD_SET (pwm
->fd
, &fds
);
1002 n
= select (pwm
->fd
+ 1, &fds
, NULL
, NULL
, &tv
);
1005 return FINISH (gpg_error_from_syserror ());
1009 if (FD_ISSET (pwm
->fd
, &fds
))
1010 rc
= parse_assuan_line (pwm
);
1013 while (!rc
&& assuan_pending_line (pwm
->ctx
))
1014 rc
= parse_assuan_line (pwm
);
1016 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1017 if (gpg_err_code (rc
) == GPG_ERR_EOF
&& pwm
->tcp
)
1028 status_cb (void *data
, const char *line
)
1032 if (!strncmp (line
, "INQUIRE_MAXLEN ", 15))
1033 pwm
->inquire_maxlen
= strtol (line
+ 15, NULL
, 10);
1035 if (pwm
->status_func
)
1036 return pwm
->status_func (pwm
->status_data
, line
);
1042 _assuan_command (pwm_t
* pwm
, assuan_context_t ctx
,
1043 char **result
, size_t * len
, const char *cmd
)
1049 return FINISH (GPG_ERR_INV_ARG
);
1051 if (strlen (cmd
) >= ASSUAN_LINELENGTH
+ 1)
1052 return FINISH (GPG_ERR_LINE_TOO_LONG
);
1056 rc
= assuan_transact (ctx
, cmd
, inquire_realloc_cb
, &data
,
1058 pwm
->pctx
== ctx
? pwm
->_inquire_func
: inquire_cb
,
1059 pwm
->pctx
== ctx
? pwm
->_inquire_data
: pwm
,
1069 pwmd_free (data
.buf
);
1077 inquire_realloc_cb (&data
, "", 1);
1080 *result
= (char *) data
.buf
;
1082 pwmd_free (data
.buf
);
1089 pwm
->inquire_maxlen
= 0;
1094 pwmd_command_ap (pwm_t
* pwm
, char **result
, size_t * rlen
,
1095 pwmd_inquire_cb_t func
, void *user
, const char *cmd
,
1103 return FINISH (GPG_ERR_INV_ARG
);
1105 return FINISH (GPG_ERR_INV_STATE
);
1108 * C99 allows the dst pointer to be null which will calculate the length
1109 * of the would-be result and return it.
1112 len
= vsnprintf (NULL
, 0, cmd
, ap
) + 1;
1113 buf
= (char *) pwmd_malloc (len
);
1117 return FINISH (GPG_ERR_ENOMEM
);
1120 len
= vsnprintf (buf
, len
, cmd
, ap2
);
1123 if (buf
[strlen (buf
) - 1] == '\n')
1124 buf
[strlen (buf
) - 1] = 0;
1125 if (buf
[strlen (buf
) - 1] == '\r')
1126 buf
[strlen (buf
) - 1] = 0;
1128 pwm
->inquire_func
= func
;
1129 pwm
->inquire_data
= user
;
1130 pwm
->inquire_sent
= 0;
1131 gpg_error_t rc
= _assuan_command (pwm
, pwm
->ctx
, result
, rlen
, buf
);
1137 pwmd_command (pwm_t
* pwm
, char **result
, size_t * len
,
1138 pwmd_inquire_cb_t func
, void *user
, const char *cmd
, ...)
1143 return FINISH (GPG_ERR_INV_ARG
);
1145 return FINISH (GPG_ERR_INV_STATE
);
1151 gpg_error_t rc
= pwmd_command_ap (pwm
, result
, len
, func
, user
, cmd
, ap
);
1157 send_pinentry_options (pwm_t
* pwm
)
1161 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1162 "OPTION disable-pinentry=0");
1163 if (!rc
&& pwm
->pinentry_tty
)
1164 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION TTYNAME=%s",
1167 if (!rc
&& pwm
->pinentry_term
)
1168 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION TTYTYPE=%s",
1169 pwm
->pinentry_term
);
1171 if (!rc
&& pwm
->pinentry_display
)
1172 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION DISPLAY=%s",
1173 pwm
->pinentry_display
);
1175 if (!rc
&& pwm
->pinentry_desc
)
1176 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION DESC=%s",
1177 pwm
->pinentry_desc
);
1179 if (!rc
&& pwm
->pinentry_lcctype
)
1180 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION LC_CTYPE=%s",
1181 pwm
->pinentry_lcctype
);
1183 if (!rc
&& pwm
->pinentry_lcmessages
)
1184 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION LC_MESSAGES=%s",
1185 pwm
->pinentry_lcmessages
);
1187 if (!rc
&& pwm
->pinentry_timeout
> 0)
1188 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1189 "OPTION pinentry-timeout=%i", pwm
->pinentry_timeout
);
1195 pwmd_socket_type (pwm_t
* pwm
, pwmd_socket_t
* result
)
1197 if (!pwm
|| !result
)
1198 return FINISH (GPG_ERR_INV_ARG
);
1200 *result
= PWMD_SOCKET_LOCAL
;
1203 return FINISH (GPG_ERR_INV_STATE
);
1205 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1207 if (pwm
->tcp
&& pwm
->tcp
->ssh
)
1208 *result
= PWMD_SOCKET_SSH
;
1211 if (pwm
->tcp
&& pwm
->tcp
->tls
)
1212 *result
= PWMD_SOCKET_TLS
;
1219 pwmd_open (pwm_t
* pwm
, const char *filename
, pwmd_inquire_cb_t cb
,
1225 if (!pwm
|| !filename
|| !*filename
)
1226 return FINISH (GPG_ERR_INV_ARG
);
1229 return FINISH (GPG_ERR_INV_STATE
);
1231 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1232 no_pinentry
= pwm
->disable_pinentry
|| pwm
->tcp
|| pwm
->local_pinentry
;
1234 no_pinentry
= pwm
->disable_pinentry
|| pwm
->local_pinentry
;
1238 rc
= send_pinentry_options (pwm
);
1240 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1241 "OPTION disable-pinentry");
1245 pwm
->pinentry_try
= 0;
1246 pwmd_free (pwm
->filename
);
1247 pwm
->filename
= pwmd_strdup (filename
);
1251 rc
= pwmd_command (pwm
, NULL
, NULL
, cb
, data
, "OPEN %s%s",
1252 (pwm
->opts
& OPT_LOCK_ON_OPEN
) ? "--lock " : "",
1255 while (gpg_err_code (rc
) == GPG_ERR_BAD_PASSPHRASE
1256 && no_pinentry
&& ++pwm
->pinentry_try
< pwm
->pinentry_tries
);
1258 pwm
->pinentry_try
= 0;
1262 pwmd_free (pwm
->filename
);
1263 pwm
->filename
= NULL
;
1271 pwmd_save (pwm_t
* pwm
, const char *args
, pwmd_inquire_cb_t cb
, void *data
)
1276 return FINISH (GPG_ERR_INV_ARG
);
1278 return FINISH (GPG_ERR_INV_STATE
);
1280 if (pwm
->disable_pinentry
|| pwm
->local_pinentry
)
1281 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION disable-pinentry");
1284 rc
= pwmd_command (pwm
, NULL
, NULL
, cb
, data
, "SAVE %s", args
? args
: "");
1290 pwmd_setopt (pwm_t
* pwm
, pwmd_option_t opt
, ...)
1298 return FINISH (GPG_ERR_INV_ARG
);
1304 case PWMD_OPTION_LOCK_ON_OPEN
:
1305 n
= va_arg (ap
, int);
1308 rc
= GPG_ERR_INV_VALUE
;
1311 pwm
->opts
|= OPT_LOCK_ON_OPEN
;
1313 pwm
->opts
&= ~OPT_LOCK_ON_OPEN
;
1316 case PWMD_OPTION_INQUIRE_TOTAL
:
1317 pwm
->inquire_total
= va_arg (ap
, size_t);
1319 case PWMD_OPTION_STATUS_CB
:
1320 pwm
->status_func
= va_arg (ap
, pwmd_status_cb_t
);
1322 case PWMD_OPTION_STATUS_DATA
:
1323 pwm
->status_data
= va_arg (ap
, void *);
1325 case PWMD_OPTION_NO_PINENTRY
:
1326 n
= va_arg (ap
, int);
1329 rc
= GPG_ERR_INV_VALUE
;
1331 pwm
->disable_pinentry
= n
;
1334 case PWMD_OPTION_LOCAL_PINENTRY
:
1335 n
= va_arg (ap
, int);
1338 rc
= GPG_ERR_INV_VALUE
;
1340 pwm
->local_pinentry
= n
;
1343 case PWMD_OPTION_PINENTRY_TIMEOUT
:
1344 n
= va_arg (ap
, int);
1347 rc
= GPG_ERR_INV_VALUE
;
1349 pwm
->pinentry_timeout
= n
;
1351 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1352 if (!rc
&& pwm
->fd
!= -1 && !pwm
->tcp
)
1354 if (!rc
&& pwm
->fd
!= -1)
1356 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1357 "OPTION pinentry-timeout=%i", pwm
->pinentry_timeout
);
1359 case PWMD_OPTION_PINENTRY_TRIES
:
1360 n
= va_arg (ap
, int);
1361 pwm
->pinentry_tries
= n
;
1363 case PWMD_OPTION_PINENTRY_PATH
:
1364 arg1
= va_arg (ap
, char *);
1365 pwmd_free (pwm
->pinentry_path
);
1366 pwm
->pinentry_path
= arg1
? _expand_homedir (arg1
, NULL
) : NULL
;
1368 case PWMD_OPTION_PINENTRY_TTY
:
1369 arg1
= va_arg (ap
, char *);
1370 pwmd_free (pwm
->pinentry_tty
);
1371 pwm
->pinentry_tty
= arg1
? pwmd_strdup (arg1
) : NULL
;
1373 case PWMD_OPTION_PINENTRY_DISPLAY
:
1374 arg1
= va_arg (ap
, char *);
1375 pwmd_free (pwm
->pinentry_display
);
1376 pwm
->pinentry_display
= arg1
? pwmd_strdup (arg1
) : NULL
;
1378 case PWMD_OPTION_PINENTRY_TERM
:
1379 arg1
= va_arg (ap
, char *);
1380 pwmd_free (pwm
->pinentry_term
);
1381 pwm
->pinentry_term
= arg1
? pwmd_strdup (arg1
) : NULL
;
1383 case PWMD_OPTION_PINENTRY_ERROR
:
1384 arg1
= va_arg (ap
, char *);
1385 pwmd_free (pwm
->pinentry_error
);
1386 pwm
->pinentry_error
= arg1
? _percent_escape (arg1
) : NULL
;
1388 case PWMD_OPTION_PINENTRY_PROMPT
:
1389 arg1
= va_arg (ap
, char *);
1390 pwmd_free (pwm
->pinentry_prompt
);
1391 pwm
->pinentry_prompt
= arg1
? _percent_escape (arg1
) : NULL
;
1393 case PWMD_OPTION_PINENTRY_DESC
:
1394 arg1
= va_arg (ap
, char *);
1395 pwmd_free (pwm
->pinentry_desc
);
1396 pwm
->pinentry_desc
= arg1
? _percent_escape (arg1
) : NULL
;
1398 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
1399 arg1
= va_arg (ap
, char *);
1400 pwmd_free (pwm
->pinentry_lcctype
);
1401 pwm
->pinentry_lcctype
= arg1
? pwmd_strdup (arg1
) : NULL
;
1403 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
1404 arg1
= va_arg (ap
, char *);
1405 pwmd_free (pwm
->pinentry_lcmessages
);
1406 pwm
->pinentry_lcmessages
= arg1
? pwmd_strdup (arg1
) : NULL
;
1408 case PWMD_OPTION_KNOWNHOST_CB
:
1409 pwm
->kh_cb
= va_arg (ap
, pwmd_knownhost_cb_t
);
1411 case PWMD_OPTION_KNOWNHOST_DATA
:
1412 pwm
->kh_data
= va_arg (ap
, void *);
1414 case PWMD_OPTION_SSH_AGENT
:
1415 pwm
->use_agent
= va_arg (ap
, int);
1417 if (pwm
->use_agent
< 0 || pwm
->use_agent
> 1)
1420 rc
= GPG_ERR_INV_VALUE
;
1423 case PWMD_OPTION_TLS_VERIFY
:
1424 pwm
->tls_verify
= va_arg (ap
, int);
1426 if (pwm
->tls_verify
< 0 || pwm
->tls_verify
> 1)
1428 pwm
->tls_verify
= 0;
1429 rc
= GPG_ERR_INV_VALUE
;
1432 case PWMD_OPTION_SOCKET_TIMEOUT
:
1433 pwm
->socket_timeout
= va_arg (ap
, int);
1434 if (pwm
->socket_timeout
< 0)
1436 pwm
->socket_timeout
= 0;
1437 rc
= GPG_ERR_INV_VALUE
;
1441 if (pwm
->tcp
&& pwm
->tcp
->ssh
&& pwm
->tcp
->ssh
->session
)
1443 pwm
->tcp
->ssh
->timeout
= pwm
->socket_timeout
;
1444 libssh2_session_set_timeout (pwm
->tcp
->ssh
->session
,
1445 pwm
->socket_timeout
* 1000);
1449 if (pwm
->tcp
&& pwm
->tcp
->tls
&& pwm
->tcp
->tls
->session
)
1450 pwm
->tcp
->tls
->timeout
= pwm
->socket_timeout
;
1453 case PWMD_OPTION_OVERRIDE_INQUIRE
:
1454 pwm
->override_inquire
= va_arg (ap
, int);
1456 if (pwm
->override_inquire
< 0 || pwm
->override_inquire
> 1)
1458 pwm
->override_inquire
= 0;
1459 rc
= GPG_ERR_INV_VALUE
;
1463 rc
= GPG_ERR_UNKNOWN_OPTION
;
1472 pwmd_new (const char *name
, pwm_t
** pwm
)
1474 pwm_t
*h
= pwmd_calloc (1, sizeof (pwm_t
));
1478 return FINISH (GPG_ERR_ENOMEM
);
1482 h
->name
= pwmd_strdup (name
);
1486 return FINISH (GPG_ERR_ENOMEM
);
1491 h
->pinentry_timeout
= -30;
1492 h
->pinentry_tries
= 3;
1493 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1494 h
->prot
= PWMD_IP_ANY
;
1497 if (ttyname (STDOUT_FILENO
))
1501 ttyname_r (STDOUT_FILENO
, buf
, sizeof (buf
));
1502 h
->pinentry_tty
= pwmd_strdup (buf
);
1503 if (!h
->pinentry_tty
)
1505 rc
= GPG_ERR_ENOMEM
;
1510 if (getenv ("TERM") && h
->pinentry_tty
)
1512 h
->pinentry_term
= pwmd_strdup (getenv ("TERM"));
1513 if (!h
->pinentry_term
)
1515 rc
= GPG_ERR_ENOMEM
;
1520 if (getenv ("DISPLAY"))
1522 h
->pinentry_display
= pwmd_strdup (getenv ("DISPLAY"));
1523 if (!h
->pinentry_display
)
1525 rc
= GPG_ERR_ENOMEM
;
1530 update_pinentry_settings (h
);
1540 pwmd_free (void *ptr
)
1546 pwmd_malloc (size_t size
)
1548 return _xmalloc (size
);
1552 pwmd_calloc (size_t nmemb
, size_t size
)
1554 return _xcalloc (nmemb
, size
);
1558 pwmd_realloc (void *ptr
, size_t size
)
1560 return _xrealloc (ptr
, size
);
1564 pwmd_strdup (const char *str
)
1571 t
= _xmalloc ((len
+ 1) * sizeof (char));
1575 for (c
= 0; c
< len
; c
++)
1583 pwmd_strdup_printf (const char *fmt
, ...)
1594 len
= vsnprintf (NULL
, 0, fmt
, ap
);
1596 buf
= pwmd_malloc (++len
);
1598 vsnprintf (buf
, len
, fmt
, ap2
);
1605 pwmd_getpin (pwm_t
* pwm
, const char *filename
, char **result
,
1606 size_t * len
, pwmd_pinentry_t which
)
1608 #ifndef WITH_PINENTRY
1609 return FINISH (GPG_ERR_NOT_IMPLEMENTED
);
1611 gpg_error_t rc
= _pwmd_getpin (pwm
, filename
, result
, len
, which
);
1620 return LIBPWMD_VERSION_STR
;
1628 #ifdef WITH_PINENTRY
1629 n
|= PWMD_FEATURE_PINENTRY
;
1632 n
|= PWMD_FEATURE_SSH
;
1635 n
|= PWMD_FEATURE_CRACK
;
1638 n
|= PWMD_FEATURE_GNUTLS
;
1644 pwmd_fd (pwm_t
* pwm
, int *fd
)
1647 return FINISH (GPG_ERR_INV_ARG
);
1650 return FINISH (GPG_ERR_INV_STATE
);