2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
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/socket.h>
40 #include <sys/types.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) \
77 ssize_t
hook_read(assuan_context_t ctx
, assuan_fd_t fd
, void *data
,
80 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
81 pwm_t
*pwm
= assuan_get_pointer(ctx
);
84 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->ssh
)
85 return read_hook_ssh(pwm
->tcp
->ssh
, fd
, data
, len
);
88 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->tls
)
89 return read_hook_tls(pwm
->tcp
->tls
, fd
, data
, len
);
93 return read((int)fd
, data
, len
);
96 ssize_t
hook_write(assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
100 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
101 pwm_t
*pwm
= assuan_get_pointer(ctx
);
104 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->ssh
)
105 return write_hook_ssh(pwm
->tcp
->ssh
, fd
, data
, len
);
108 if (pwm
&& pwm
->tcp
&& pwm
->tcp
->tls
)
109 return write_hook_tls(pwm
->tcp
->tls
, fd
, data
, len
);
113 /* libassuan cannot handle EAGAIN when doing writes. */
115 wrote
= write((int)fd
, data
, len
);
117 if (wrote
== -1 && errno
== EAGAIN
) {
120 } while (wrote
== -1 && errno
== EAGAIN
);
125 pid_t
hook_waitpid(assuan_context_t ctx
, pid_t pid
, int action
, int *status
,
128 return waitpid(pid
, status
, options
);
131 gpg_error_t
pwmd_init()
133 static int initialized
;
136 // May be called more than once.
137 gnutls_global_init();
147 bindtextdomain("libpwmd", LOCALEDIR
);
160 gnutls_global_deinit();
164 gpg_error_t
_connect_finalize(pwm_t
*pwm
)
168 int n
= assuan_get_active_fds(pwm
->ctx
, 0, active
, N_ARRAY(active
));
171 return GPG_ERR_EBADFD
;
175 pwm
->pinentry_pid
= -1;
179 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION NAME=%s", pwm
->name
);
184 static gpg_error_t
connect_uds(pwm_t
*pwm
, const char *path
)
186 char *socketpath
= NULL
;
192 return GPG_ERR_INV_ARG
;
194 pwbuf
= _getpwuid(&pw
);
196 return gpg_error_from_syserror();
199 socketpath
= pwmd_strdup_printf("%s/.pwmd/socket", pw
.pw_dir
);
201 socketpath
= _expand_homedir((char *)path
, &pw
);
205 return GPG_ERR_ENOMEM
;
207 rc
= assuan_socket_connect(pwm
->ctx
, socketpath
, ASSUAN_INVALID_FD
, 0);
208 pwmd_free(socketpath
);
209 return rc
? rc
: _connect_finalize(pwm
);
212 static gpg_error_t
init_handle(pwm_t
*pwm
)
215 static struct assuan_malloc_hooks mhooks
= {
216 pwmd_malloc
, pwmd_realloc
, pwmd_free
218 static struct assuan_system_hooks shooks
= {
219 ASSUAN_SYSTEM_HOOKS_VERSION
,
227 NULL
, //sendmsg both are used for FD passing
235 rc
= assuan_new_ext(&pwm
->ctx
, GPG_ERR_SOURCE_DEFAULT
, &mhooks
, NULL
, NULL
);
239 assuan_set_pointer(pwm
->ctx
, pwm
);
240 assuan_ctx_set_system_hooks(pwm
->ctx
, &shooks
);
244 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
245 void free_tcp(struct tcp_s
*tcp
)
251 _free_ssh_conn(tcp
->ssh
);
257 pwmd_free(tcp
->host
);
259 freeaddrinfo(tcp
->addrs
);
270 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
271 gpg_error_t
tcp_connect_common(pwm_t
*pwm
)
273 struct addrinfo hints
= {0};
280 hints
.ai_family
= AF_UNSPEC
;
283 hints
.ai_family
= AF_INET
;
286 hints
.ai_family
= AF_INET6
;
290 hints
.ai_socktype
= SOCK_STREAM
;
291 snprintf(portstr
, sizeof(portstr
), "%i", pwm
->tcp
->port
);
292 n
= getaddrinfo(pwm
->tcp
->host
, portstr
, &hints
, &pwm
->tcp
->addrs
);
294 fprintf(stderr
, "%s\n", gai_strerror(n
));
295 return GPG_ERR_UNKNOWN_HOST
; //FIXME
298 for (pwm
->tcp
->addr
= pwm
->tcp
->addrs
; pwm
->tcp
->addr
;
299 pwm
->tcp
->addr
= pwm
->tcp
->addrs
->ai_next
) {
300 pwm
->tcp
->fd
= socket(pwm
->tcp
->addr
->ai_family
, SOCK_STREAM
, 0);
301 if (pwm
->tcp
->fd
== -1) {
302 rc
= gpg_error_from_syserror();
303 if (pwm
->tcp
->addr
== pwm
->tcp
->addrs
->ai_next
)
308 if (connect(pwm
->tcp
->fd
, pwm
->tcp
->addr
->ai_addr
,
309 pwm
->tcp
->addr
->ai_family
== AF_INET6
310 ? sizeof(struct sockaddr_in6
)
311 : sizeof(struct sockaddr
)) == -1) {
312 rc
= gpg_error_from_syserror();
315 if (pwm
->tcp
->addr
== pwm
->tcp
->addrs
->ai_next
)
328 gpg_error_t
pwmd_connect(pwm_t
*pwm
, const char *url
, ...)
334 return FINISH(GPG_ERR_INV_ARG
);
335 else if (!pwm
->ctx
) {
336 rc
= init_handle(pwm
);
341 rc
= GPG_ERR_UNSUPPORTED_PROTOCOL
;
344 rc
= connect_uds(pwm
, p
);
345 else if (!p
|| !strncmp(p
, "file://", 7)) {
348 rc
= connect_uds(pwm
, p
);
350 else if (!strncmp(p
, "ssh://", 6) || !strncmp(p
, "ssh6://", 7) ||
351 !strncmp(p
, "ssh4://", 7)) {
353 return FINISH(GPG_ERR_NOT_IMPLEMENTED
);
357 char *username
= NULL
;
359 if (!strncmp(p
, "ssh6://", 7)) {
360 pwm
->prot
= PWMD_IPV6
;
363 else if (!strncmp(p
, "ssh4://", 7)) {
364 pwm
->prot
= PWMD_IPV4
;
368 pwm
->prot
= PWMD_IP_ANY
;
372 rc
= _parse_ssh_url(p
, &host
, &port
, &username
);
375 char *identity
= NULL
;
376 char *knownhosts
= NULL
;
379 identity
= va_arg(ap
, char *);
381 if (!identity
&& !pwm
->use_agent
)
382 rc
= GPG_ERR_INV_ARG
;
384 knownhosts
= va_arg(ap
, char *);
389 rc
= _do_ssh_connect(pwm
, host
, port
, identity
, username
,
392 rc
= _connect_finalize(pwm
);
405 else if (!strncmp(p
, "tls://", 6) || !strncmp(p
, "tls6://", 7) ||
406 !strncmp(p
, "tls4://", 7)) {
408 return FINISH(GPG_ERR_NOT_IMPLEMENTED
);
413 if (!strncmp(p
, "tls6://", 7)) {
414 pwm
->prot
= PWMD_IPV6
;
417 else if (!strncmp(p
, "tls4://", 7)) {
418 pwm
->prot
= PWMD_IPV4
;
422 pwm
->prot
= PWMD_IP_ANY
;
426 rc
= _parse_tls_url(p
, &host
, &port
);
429 char *clientcert
= NULL
;
430 char *clientkey
= NULL
;
433 char *server_fp
= NULL
;
436 clientcert
= va_arg(ap
, char *);
439 rc
= GPG_ERR_INV_ARG
;
441 clientkey
= va_arg(ap
, char *);
443 rc
= GPG_ERR_INV_ARG
;
445 cacert
= va_arg(ap
, char *);
447 rc
= GPG_ERR_INV_ARG
;
449 prio
= va_arg(ap
, char *);
450 server_fp
= va_arg(ap
, char *);
458 rc
= _do_tls_connect(pwm
, host
, port
, clientcert
, clientkey
,
459 cacert
, prio
, server_fp
, pwm
->tls_verify
);
461 rc
= _connect_finalize(pwm
);
477 static void disconnect(pwm_t
*pwm
)
483 assuan_release(pwm
->ctx
);
485 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
493 void pwmd_close(pwm_t
*pwm
)
499 pwmd_free(pwm
->pinentry_error
);
500 pwmd_free(pwm
->pinentry_desc
);
501 pwmd_free(pwm
->pinentry_prompt
);
502 pwmd_free(pwm
->pinentry_tty
);
503 pwmd_free(pwm
->pinentry_display
);
504 pwmd_free(pwm
->pinentry_term
);
505 pwmd_free(pwm
->pinentry_lcctype
);
506 pwmd_free(pwm
->pinentry_lcmessages
);
507 pwmd_free(pwm
->filename
);
508 pwmd_free(pwm
->name
);
512 _pinentry_disconnect(pwm
);
518 static gpg_error_t
inquire_realloc_cb(void *data
, const void *buffer
,
521 membuf_t
*mem
= (membuf_t
*)data
;
527 if ((p
= pwmd_realloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
528 return gpg_error(GPG_ERR_ENOMEM
);
531 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
536 static gpg_error_t
get_password(pwm_t
*pwm
, char **result
, pwmd_pinentry_t w
,
539 char buf
[LINE_MAX
] = {0}, *p
;
540 struct termios told
, tnew
;
545 if (!isatty(STDIN_FILENO
)) {
546 fprintf(stderr
, N_("Input is not from a terminal! Failing.\n"));
547 return GPG_ERR_ENOTTY
;
551 if (tcgetattr(STDIN_FILENO
, &told
) == -1)
552 return gpg_error_from_syserror();
554 memcpy(&tnew
, &told
, sizeof(struct termios
));
555 tnew
.c_lflag
&= ~(ECHO
);
556 tnew
.c_lflag
|= ICANON
|ECHONL
;
558 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &tnew
) == -1) {
561 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
562 return gpg_error_from_errno(n
);
567 case PWMD_PINENTRY_OPEN
:
568 fprintf(stderr
, N_("Password for %s: "), pwm
->filename
);
570 case PWMD_PINENTRY_OPEN_FAILED
:
571 fprintf(stderr
, N_("Invalid password. Password for %s: "),
574 case PWMD_PINENTRY_SAVE
:
575 fprintf(stderr
, N_("New password for %s: "), pwm
->filename
);
577 case PWMD_PINENTRY_SAVE_CONFIRM
:
578 fprintf(stderr
, N_("Confirm password: "));
584 if ((p
= fgets(buf
, sizeof(buf
), stdin
)) == NULL
) {
585 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
590 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
594 return GPG_ERR_CANCELED
;
597 p
[strlen(p
) - 1] = 0;
600 key
= pwmd_strdup_printf("%s", p
);
601 memset(&buf
, 0, sizeof(buf
));
604 return GPG_ERR_ENOMEM
;
611 gpg_error_t
pwmd_password(pwm_t
*pwm
, const char *keyword
, char **data
,
615 int new_password
= 0;
617 char *password
= NULL
, *newpass
= NULL
;
620 if (!strcmp(keyword
, "NEW_PASSPHRASE"))
623 if (!new_password
&& pwm
->pinentry_try
)
627 if (pwm
->disable_pinentry
) {
628 rc
= get_password(pwm
, &password
,
629 new_password
? PWMD_PINENTRY_SAVE
: PWMD_PINENTRY_OPEN
, 0);
630 if (!rc
&& new_password
)
631 rc
= get_password(pwm
, &newpass
, PWMD_PINENTRY_SAVE_CONFIRM
, 0);
634 pwmd_pinentry_t which
;
637 which
= new_password
? PWMD_PINENTRY_SAVE_FAILED
: PWMD_PINENTRY_OPEN_FAILED
;
639 which
= new_password
? PWMD_PINENTRY_SAVE
: PWMD_PINENTRY_OPEN
;
641 rc
= pwmd_getpin(pwm
, pwm
->filename
, &password
, &len
, which
);
642 if (!rc
&& new_password
)
643 rc
= pwmd_getpin(pwm
, pwm
->filename
, &newpass
, &len
,
644 PWMD_PINENTRY_SAVE_CONFIRM
);
647 if (!rc
&& new_password
) {
648 if ((!password
&& newpass
) || (!newpass
&& password
)
649 || strcmp(newpass
, password
)) {
650 if (pwm
->disable_pinentry
)
651 fprintf(stderr
, N_("Passphrases do not match.\n"));
655 password
= newpass
= NULL
;
661 (void)pwmd_getpin(pwm
, pwm
->filename
, NULL
, NULL
, PWMD_PINENTRY_CLOSE
);
664 // An empty passphrase on a protected key is not allowed by gpg-agent.
665 if (!password
&& !new_password
)
666 rc
= GPG_ERR_CANCELED
;
669 *size
= password
? strlen(password
) : 0;
676 static gpg_error_t
inquire_cb(void *data
, const char *keyword
)
678 pwm_t
*pwm
= (pwm_t
*)data
;
683 /* Shouldn't get this far without a callback. */
684 if (!pwm
->override_inquire
&& !pwm
->inquire_func
)
685 return gpg_error(GPG_ERR_ASS_NO_INQUIRE_CB
);
691 int new_password
= 0;
695 if (!strcmp(keyword
, "PASSPHRASE"))
697 else if (!strcmp(keyword
, "NEW_PASSPHRASE"))
700 if (!pwm
->override_inquire
&& (is_password
|| new_password
)) {
702 rc
= pwmd_password(data
, keyword
, &result
, &len
);
707 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
, &result
,
711 if (rc
&& gpg_err_code(rc
) != GPG_ERR_EOF
) {
712 gpg_error_t trc
= rc
;
714 /* Cancel this inquire. */
715 rc
= assuan_send_data(pwm
->ctx
, NULL
, 1);
720 /* There is a bug (or feature?) in assuan_send_data() that
721 * when cancelling an inquire the next read from the server is
722 * not done until the next command making the next command
723 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
725 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
727 /* Restore the original error. This differs from the error
728 * returned from the pwmd command (GPG_ERR_CANCELED). This
729 * error is returned to the calling function.
738 if (gpg_err_code(rc
) == GPG_ERR_EOF
|| !rc
) {
739 if (len
<= 0 && !result
) {
743 else if ((len
<= 0 && result
) || (len
&& !result
)) {
744 rc
= gpg_error(GPG_ERR_INV_ARG
);
748 if (pwm
->inquire_maxlen
749 && pwm
->inquire_sent
+len
> pwm
->inquire_maxlen
) {
750 rc
= gpg_error(GPG_ERR_TOO_LARGE
);
752 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
,
757 arc
= assuan_send_data(pwm
->ctx
, result
, len
);
758 if (gpg_err_code(rc
) == GPG_ERR_EOF
) {
769 pwm
->inquire_sent
+= len
;
771 if (pwm
->status_func
) {
772 char buf
[ASSUAN_LINELENGTH
];
774 snprintf(buf
, sizeof(buf
), "XFER %lu %lu", pwm
->inquire_sent
,
776 rc
= pwm
->status_func(pwm
->status_data
, buf
);
789 static gpg_error_t
parse_assuan_line(pwm_t
*pwm
)
795 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
797 if (line
[0] == 'O' && line
[1] == 'K' &&
798 (line
[2] == 0 || line
[2] == ' ')) {
800 else if (line
[0] == '#') {
802 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' ')) {
803 if (pwm
->status_func
) {
804 rc
= pwm
->status_func(pwm
->status_data
,
805 line
[1] == 0 ? line
+1 : line
+2);
808 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
809 (line
[3] == 0 || line
[3] == ' ')) {
811 rc
= strtol(line
, NULL
, 10);
818 static void reset_handle_state(pwm_t
*pwm
, int done
)
820 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
831 static void reset_handle(pwm_t
*h
)
836 _pinentry_disconnect(h
);
838 reset_handle_state(h
, 0);
841 gpg_error_t
pwmd_disconnect(pwm_t
*pwm
)
844 return FINISH(GPG_ERR_INV_ARG
);
846 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
847 if (pwm
->fd
== -1 && pwm
->tcp
&& pwm
->tcp
->fd
== -1)
851 return FINISH(GPG_ERR_INV_STATE
);
860 /* Note that this should only be called when not in a command. */
861 gpg_error_t
pwmd_process(pwm_t
*pwm
)
865 struct timeval tv
= {0, 0};
869 return FINISH(GPG_ERR_INV_ARG
);
871 return FINISH(GPG_ERR_INV_STATE
);
873 #if defined(WITH_SSH)
874 if (pwm
->tcp
&& pwm
->tcp
->ssh
&& pwm
->keepalive_interval
) {
876 int n
= libssh2_keepalive_send(pwm
->tcp
->ssh
->session
, &to
);
879 return FINISH(GPG_ERR_ETIMEDOUT
);
881 if (pwm
->tcp
->ssh
->keepalive_prev
&&
882 to
> pwm
->tcp
->ssh
->keepalive_prev
) {
883 pwm
->tcp
->ssh
->keepalive_prev
= to
;
884 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "NOP");
889 pwm
->tcp
->ssh
->keepalive_prev
= to
;
894 FD_SET(pwm
->fd
, &fds
);
895 n
= select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
898 return FINISH(gpg_error_from_syserror());
901 if (FD_ISSET(pwm
->fd
, &fds
))
902 rc
= parse_assuan_line(pwm
);
905 while (!rc
&& assuan_pending_line(pwm
->ctx
))
906 rc
= parse_assuan_line(pwm
);
911 static gpg_error_t
status_cb(void *data
, const char *line
)
915 if (!strncmp(line
, "INQUIRE_MAXLEN ", 15))
916 pwm
->inquire_maxlen
= strtol(line
+15, NULL
, 10);
918 if (pwm
->status_func
)
919 return pwm
->status_func(pwm
->status_data
, line
);
924 gpg_error_t
_assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
925 char **result
, size_t *len
, const char *cmd
)
931 return FINISH(GPG_ERR_INV_ARG
);
933 if (strlen(cmd
) >= ASSUAN_LINELENGTH
+1)
934 return FINISH(GPG_ERR_LINE_TOO_LONG
);
938 rc
= assuan_transact(ctx
, cmd
, inquire_realloc_cb
, &data
,
940 pwm
->pctx
== ctx
? pwm
->_inquire_func
: inquire_cb
,
941 pwm
->pctx
== ctx
? pwm
->_inquire_data
: pwm
,
955 inquire_realloc_cb(&data
, "", 1);
958 *result
= (char *)data
.buf
;
967 pwm
->inquire_maxlen
= 0;
971 gpg_error_t
pwmd_command_ap(pwm_t
*pwm
, char **result
, size_t *rlen
,
972 pwmd_inquire_cb_t func
, void *user
, const char *cmd
, va_list ap
)
979 return FINISH(GPG_ERR_INV_ARG
);
981 return FINISH(GPG_ERR_INV_STATE
);
984 * C99 allows the dst pointer to be null which will calculate the length
985 * of the would-be result and return it.
988 len
= vsnprintf(NULL
, 0, cmd
, ap
)+1;
989 buf
= (char *)pwmd_malloc(len
);
992 return FINISH(GPG_ERR_ENOMEM
);
995 len
= vsnprintf(buf
, len
, cmd
, ap2
);
998 if (buf
[strlen(buf
)-1] == '\n')
999 buf
[strlen(buf
)-1] = 0;
1000 if (buf
[strlen(buf
)-1] == '\r')
1001 buf
[strlen(buf
)-1] = 0;
1003 pwm
->inquire_func
= func
;
1004 pwm
->inquire_data
= user
;
1005 pwm
->inquire_sent
= 0;
1006 gpg_error_t rc
= _assuan_command(pwm
, pwm
->ctx
, result
, rlen
, buf
);
1011 gpg_error_t
pwmd_command(pwm_t
*pwm
, char **result
, size_t *len
,
1012 pwmd_inquire_cb_t func
, void *user
, const char *cmd
, ...)
1017 return FINISH(GPG_ERR_INV_ARG
);
1019 return FINISH(GPG_ERR_INV_STATE
);
1025 gpg_error_t rc
= pwmd_command_ap(pwm
, result
, len
, func
, user
, cmd
, ap
);
1030 static gpg_error_t
send_pinentry_options(pwm_t
*pwm
)
1034 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION disable-pinentry=0");
1038 if (pwm
->pinentry_tty
) {
1039 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION TTYNAME=%s", pwm
->pinentry_tty
);
1044 if (pwm
->pinentry_term
) {
1045 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION TTYTYPE=%s", pwm
->pinentry_term
);
1050 if (pwm
->pinentry_display
) {
1051 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION DISPLAY=%s",
1052 pwm
->pinentry_display
);
1057 if (pwm
->pinentry_desc
) {
1058 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION DESC=%s",
1059 pwm
->pinentry_desc
);
1064 if (pwm
->pinentry_lcctype
) {
1065 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION LC_CTYPE=%s",
1066 pwm
->pinentry_lcctype
);
1071 if (pwm
->pinentry_lcmessages
) {
1072 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION LC_MESSAGES=%s",
1073 pwm
->pinentry_lcmessages
);
1081 gpg_error_t
pwmd_socket_type(pwm_t
*pwm
, pwmd_socket_t
*result
)
1083 if (!pwm
|| !result
)
1084 return FINISH(GPG_ERR_INV_ARG
);
1086 *result
= PWMD_SOCKET_LOCAL
;
1088 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1089 if ((pwm
->fd
== -1 && (!pwm
->tcp
1097 (pwm
->fd
== -1 && pwm
->tcp
&& pwm
->tcp
->fd
== -1))
1098 return FINISH(GPG_ERR_INV_STATE
);
1101 return FINISH(GPG_ERR_INV_STATE
);
1104 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1106 if (pwm
->tcp
&& pwm
->tcp
->ssh
)
1107 *result
= PWMD_SOCKET_SSH
;
1110 if (pwm
->tcp
&& pwm
->tcp
->tls
)
1111 *result
= PWMD_SOCKET_TLS
;
1117 gpg_error_t
pwmd_open(pwm_t
*pwm
, const char *filename
, pwmd_inquire_cb_t cb
,
1121 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1122 int no_pinentry
= pwm
->disable_pinentry
|| pwm
->tcp
|| pwm
->local_pinentry
;
1124 int no_pinentry
= pwm
->disable_pinentry
|| pwm
->local_pinentry
;
1127 if (!pwm
|| !filename
|| !*filename
)
1128 return FINISH(GPG_ERR_INV_ARG
);
1131 return FINISH(GPG_ERR_INV_STATE
);
1134 rc
= send_pinentry_options(pwm
);
1136 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION disable-pinentry");
1139 pwm
->pinentry_try
= 0;
1140 pwmd_free(pwm
->filename
);
1141 pwm
->filename
= pwmd_strdup(filename
);
1144 rc
= pwmd_command(pwm
, NULL
, NULL
, cb
, data
, "OPEN %s%s",
1145 (pwm
->opts
& OPT_LOCK_ON_OPEN
) ? "--lock " : "",
1147 } while (gpg_err_code(rc
) == GPG_ERR_BAD_PASSPHRASE
1148 && no_pinentry
&& ++pwm
->pinentry_try
< pwm
->pinentry_tries
);
1150 pwm
->pinentry_try
= 0;
1153 pwmd_free(pwm
->filename
);
1154 pwm
->filename
= NULL
;
1161 gpg_error_t
pwmd_save(pwm_t
*pwm
, const char *args
, pwmd_inquire_cb_t cb
,
1167 return FINISH(GPG_ERR_INV_ARG
);
1169 return FINISH(GPG_ERR_INV_STATE
);
1171 rc
= pwmd_command(pwm
, NULL
, NULL
, cb
, data
, "SAVE %s",
1176 gpg_error_t
pwmd_setopt(pwm_t
*pwm
, pwmd_option_t opt
, ...)
1184 return FINISH(GPG_ERR_INV_ARG
);
1189 case PWMD_OPTION_LOCK_ON_OPEN
:
1190 n
= va_arg(ap
, int);
1193 rc
= GPG_ERR_INV_VALUE
;
1196 pwm
->opts
|= OPT_LOCK_ON_OPEN
;
1198 pwm
->opts
&= ~OPT_LOCK_ON_OPEN
;
1201 case PWMD_OPTION_INQUIRE_TOTAL
:
1202 pwm
->inquire_total
= va_arg(ap
, size_t);
1204 case PWMD_OPTION_STATUS_CB
:
1205 pwm
->status_func
= va_arg(ap
, pwmd_status_cb_t
);
1207 case PWMD_OPTION_STATUS_DATA
:
1208 pwm
->status_data
= va_arg(ap
, void *);
1210 case PWMD_OPTION_NO_PINENTRY
:
1211 n
= va_arg(ap
, int);
1214 rc
= GPG_ERR_INV_VALUE
;
1216 pwm
->disable_pinentry
= n
;
1219 case PWMD_OPTION_LOCAL_PINENTRY
:
1220 n
= va_arg(ap
, int);
1223 rc
= GPG_ERR_INV_VALUE
;
1225 pwm
->local_pinentry
= n
;
1228 case PWMD_OPTION_PINENTRY_TIMEOUT
:
1229 n
= va_arg(ap
, int);
1232 rc
= GPG_ERR_INV_VALUE
;
1234 pwm
->pinentry_timeout
= n
;
1237 case PWMD_OPTION_PINENTRY_TRIES
:
1238 n
= va_arg(ap
, int);
1239 pwm
->pinentry_tries
= n
;
1241 case PWMD_OPTION_PINENTRY_PATH
:
1242 arg1
= va_arg(ap
, char *);
1243 pwmd_free(pwm
->pinentry_path
);
1244 pwm
->pinentry_path
= arg1
? _expand_homedir(arg1
, NULL
) : NULL
;
1246 case PWMD_OPTION_PINENTRY_TTY
:
1247 arg1
= va_arg(ap
, char *);
1248 pwmd_free(pwm
->pinentry_tty
);
1249 pwm
->pinentry_tty
= arg1
? pwmd_strdup(arg1
) : NULL
;
1251 case PWMD_OPTION_PINENTRY_DISPLAY
:
1252 arg1
= va_arg(ap
, char *);
1253 pwmd_free(pwm
->pinentry_display
);
1254 pwm
->pinentry_display
= arg1
? pwmd_strdup(arg1
) : NULL
;
1256 case PWMD_OPTION_PINENTRY_TERM
:
1257 arg1
= va_arg(ap
, char *);
1258 pwmd_free(pwm
->pinentry_term
);
1259 pwm
->pinentry_term
= arg1
? pwmd_strdup(arg1
) : NULL
;
1261 case PWMD_OPTION_PINENTRY_ERROR
:
1262 arg1
= va_arg(ap
, char *);
1263 pwmd_free(pwm
->pinentry_error
);
1264 pwm
->pinentry_error
= arg1
? _percent_escape(arg1
) : NULL
;
1266 case PWMD_OPTION_PINENTRY_PROMPT
:
1267 arg1
= va_arg(ap
, char *);
1268 pwmd_free(pwm
->pinentry_prompt
);
1269 pwm
->pinentry_prompt
= arg1
? _percent_escape(arg1
) : NULL
;
1271 case PWMD_OPTION_PINENTRY_DESC
:
1272 arg1
= va_arg(ap
, char *);
1273 pwmd_free(pwm
->pinentry_desc
);
1274 pwm
->pinentry_desc
= arg1
? _percent_escape(arg1
) : NULL
;
1276 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
1277 arg1
= va_arg(ap
, char *);
1278 pwmd_free(pwm
->pinentry_lcctype
);
1279 pwm
->pinentry_lcctype
= arg1
? pwmd_strdup(arg1
) : NULL
;
1281 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
1282 arg1
= va_arg(ap
, char *);
1283 pwmd_free(pwm
->pinentry_lcmessages
);
1284 pwm
->pinentry_lcmessages
= arg1
? pwmd_strdup(arg1
) : NULL
;
1287 case PWMD_OPTION_KNOWNHOST_CB
:
1288 pwm
->kh_cb
= va_arg(ap
, pwmd_knownhost_cb_t
);
1290 case PWMD_OPTION_KNOWNHOST_DATA
:
1291 pwm
->kh_data
= va_arg(ap
, void *);
1293 case PWMD_OPTION_SSH_AGENT
:
1294 pwm
->use_agent
= va_arg(ap
, int);
1296 if (pwm
->use_agent
< 0 || pwm
->use_agent
> 1) {
1298 rc
= GPG_ERR_INV_VALUE
;
1302 case PWMD_OPTION_SSH_TIMEOUT
:
1303 pwm
->ssh_timeout
= va_arg(ap
, int);
1305 if (pwm
->ssh_timeout
< 0) {
1306 pwm
->ssh_timeout
= 0;
1307 rc
= GPG_ERR_INV_VALUE
;
1309 else if (pwm
->tcp
&& pwm
->tcp
->ssh
&& pwm
->tcp
->ssh
->session
)
1310 libssh2_session_set_timeout(pwm
->tcp
->ssh
->session
,
1311 pwm
->ssh_timeout
*1000);
1314 case PWMD_OPTION_SSH_KEEPALIVE
:
1315 pwm
->keepalive_interval
= va_arg(ap
, int);
1317 if (pwm
->keepalive_interval
< 0) {
1318 pwm
->keepalive_interval
= 0;
1319 rc
= GPG_ERR_INV_VALUE
;
1321 else if (pwm
->tcp
&& pwm
->tcp
->ssh
&& pwm
->tcp
->ssh
->session
)
1322 libssh2_keepalive_config(pwm
->tcp
->ssh
->session
, 1,
1323 pwm
->keepalive_interval
);
1327 case PWMD_OPTION_KNOWNHOST_CB
:
1328 case PWMD_OPTION_KNOWNHOST_DATA
:
1329 case PWMD_OPTION_SSH_AGENT
:
1330 case PWMD_OPTION_SSH_TIMEOUT
:
1331 rc
= GPG_ERR_NOT_IMPLEMENTED
;
1335 case PWMD_OPTION_TLS_VERIFY
:
1336 pwm
->tls_verify
= va_arg(ap
, int);
1338 if (pwm
->tls_verify
< 0 || pwm
->tls_verify
> 1) {
1339 pwm
->tls_verify
= 0;
1340 rc
= GPG_ERR_INV_VALUE
;
1344 case PWMD_OPTION_OVERRIDE_INQUIRE
:
1345 pwm
->override_inquire
= va_arg(ap
, int);
1347 if (pwm
->override_inquire
< 0 || pwm
->override_inquire
> 1) {
1348 pwm
->override_inquire
= 0;
1349 rc
= GPG_ERR_INV_VALUE
;
1353 rc
= GPG_ERR_UNKNOWN_OPTION
;
1361 gpg_error_t
pwmd_new(const char *name
, pwm_t
**pwm
)
1363 pwm_t
*h
= pwmd_calloc(1, sizeof(pwm_t
));
1367 return FINISH(GPG_ERR_ENOMEM
);
1370 h
->name
= pwmd_strdup(name
);
1373 return FINISH(GPG_ERR_ENOMEM
);
1378 h
->pinentry_timeout
= -30;
1379 h
->pinentry_tries
= 3;
1380 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1381 h
->prot
= PWMD_IP_ANY
;
1384 if (ttyname(STDOUT_FILENO
)) {
1387 ttyname_r(STDOUT_FILENO
, buf
, sizeof(buf
));
1388 h
->pinentry_tty
= pwmd_strdup(buf
);
1389 if (!h
->pinentry_tty
) {
1390 rc
= GPG_ERR_ENOMEM
;
1395 if (getenv("TERM") && h
->pinentry_tty
) {
1396 h
->pinentry_term
= pwmd_strdup(getenv("TERM"));
1397 if (!h
->pinentry_term
) {
1398 rc
= GPG_ERR_ENOMEM
;
1403 if (getenv("DISPLAY")) {
1404 h
->pinentry_display
= pwmd_strdup(getenv("DISPLAY"));
1405 if (!h
->pinentry_display
) {
1406 rc
= GPG_ERR_ENOMEM
;
1411 update_pinentry_settings(h
);
1420 void pwmd_free(void *ptr
)
1425 void *pwmd_malloc(size_t size
)
1427 return _xmalloc(size
);
1430 void *pwmd_calloc(size_t nmemb
, size_t size
)
1432 return _xcalloc(nmemb
, size
);
1435 void *pwmd_realloc(void *ptr
, size_t size
)
1437 return _xrealloc(ptr
, size
);
1440 char *pwmd_strdup(const char *str
)
1447 t
= _xmalloc((len
+1)*sizeof(char));
1451 for (c
= 0; c
< len
; c
++)
1458 char *pwmd_strdup_printf(const char *fmt
, ...)
1469 len
= vsnprintf(NULL
, 0, fmt
, ap
);
1471 buf
= pwmd_malloc(++len
);
1473 vsnprintf(buf
, len
, fmt
, ap2
);
1479 gpg_error_t
pwmd_getpin(pwm_t
*pwm
, const char *filename
, char **result
,
1480 size_t *len
, pwmd_pinentry_t which
)
1482 #ifndef WITH_PINENTRY
1483 return FINISH(GPG_ERR_NOT_IMPLEMENTED
);
1485 gpg_error_t rc
= _pwmd_getpin(pwm
, filename
, result
, len
, which
);
1491 const char *pwmd_version()
1493 return LIBPWMD_VERSION_STR
;
1496 unsigned int pwmd_features()
1500 #ifdef WITH_PINENTRY
1501 n
|= PWMD_FEATURE_PINENTRY
;
1504 n
|= PWMD_FEATURE_SSH
;
1507 n
|= PWMD_FEATURE_CRACK
;
1510 n
|= PWMD_FEATURE_GNUTLS
;
1515 gpg_error_t
pwmd_fd(pwm_t
*pwm
, int *fd
)
1518 return FINISH(GPG_ERR_INV_ARG
);
1520 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1521 if (pwm
->tcp
&& pwm
->tcp
->fd
== -1 && pwm
->fd
== -1)
1522 return GPG_ERR_INV_STATE
;
1524 *fd
= pwm
->tcp
&& pwm
->tcp
->fd
!= -1 ? pwm
->tcp
->fd
: pwm
->fd
;
1527 return FINISH(GPG_ERR_INV_STATE
);