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>
39 #include <netinet/in.h>
40 #include <sys/socket.h>
52 #define DNS_USE_GETTIMEOFDAY_FOR_ID 1
54 #include <arpa/nameser.h>
66 #define N_(msgid) dgettext("libpwmd", msgid)
73 static int gelapsed
, gtimeout
;
74 static gpg_error_t
pinentry_command(pwm_t
*pwm
, char **result
, const char *cmd
);
75 static gpg_error_t global_error
;
78 const char *pwmd_strerror(gpg_error_t e
)
80 gpg_err_code_t code
= gpg_err_code(e
);
82 if (code
>= GPG_ERR_USER_1
&& code
< gpg_err_code(EPWMD_MAX
)) {
86 return N_("Unknown error");
88 return N_("No cache slots available");
90 return N_("Recursion loop");
92 return N_("No file is open");
94 return N_("General LibXML error");
96 return N_("File modified");
98 return N_("Access denied");
102 return gpg_strerror(e
);
105 gpg_error_t
pwmd_init()
107 static int initialized
;
116 bindtextdomain("libpwmd", LOCALEDIR
);
119 assuan_set_malloc_hooks(xmalloc
, xrealloc
, xfree
);
120 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT
);
125 static pwm_t
*_socket_connect_finalize(pwm_t
*pwm
, assuan_context_t ctx
)
128 int n
= assuan_get_active_fds(ctx
, 0, active
, sizeof(active
));
130 pwm
->fd
= n
<= 0 ? -1 : dup(active
[0]);
134 pwm
->pinentry_tries
= 3;
136 assuan_set_pointer(ctx
, pwm
);
141 static int read_hook(assuan_context_t ctx
, assuan_fd_t fd
, void *data
,
142 size_t len
, ssize_t
*ret
)
144 pwm_t
*pwm
= assuan_get_pointer(ctx
);
146 if (!pwm
|| !pwm
->tcp_conn
)
147 *ret
= read((int)fd
, data
, len
);
150 *ret
= libssh2_channel_read(pwm
->tcp_conn
->channel
, data
, len
);
151 } while (*ret
== LIBSSH2_ERROR_EAGAIN
);
154 return *ret
<= 0 ? 0 : 1;
157 static int write_hook(assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
158 size_t len
, ssize_t
*ret
)
160 pwm_t
*pwm
= assuan_get_pointer(ctx
);
162 if (!pwm
|| !pwm
->tcp_conn
)
163 *ret
= write((int)fd
, data
, len
);
166 *ret
= libssh2_channel_write(pwm
->tcp_conn
->channel
, data
, len
);
167 } while (*ret
== LIBSSH2_ERROR_EAGAIN
);
170 return *ret
<= 0 ? 0 : 1;
173 static void _ssh_deinit(pwmd_tcp_conn_t
*conn
);
174 static void free_tcp_conn(pwmd_tcp_conn_t
*conn
)
179 if (conn
->username
) {
180 xfree(conn
->username
);
181 conn
->username
= NULL
;
184 if (conn
->known_hosts
) {
185 xfree(conn
->known_hosts
);
186 conn
->known_hosts
= NULL
;
189 if (conn
->identity
) {
190 xfree(conn
->identity
);
191 conn
->identity
= NULL
;
194 if (conn
->identity_pub
) {
195 xfree(conn
->identity_pub
);
196 conn
->identity_pub
= NULL
;
205 xfree(conn
->hostkey
);
206 conn
->hostkey
= NULL
;
210 ares_destroy(conn
->chan
);
215 ares_free_hostent(conn
->he
);
230 static void _ssh_deinit(pwmd_tcp_conn_t
*conn
)
236 libssh2_channel_free(conn
->channel
);
239 libssh2_session_disconnect(conn
->session
, "Bye!");
240 libssh2_session_free(conn
->session
);
243 conn
->session
= NULL
;
244 conn
->channel
= NULL
;
248 static void _ssh_assuan_deinit(assuan_context_t ctx
)
250 pwm_t
*pwm
= assuan_get_pointer(ctx
);
252 _ssh_deinit(pwm
->tcp_conn
);
253 pwm
->tcp_conn
= NULL
;
257 * Sets common options from both pwmd_tcp_connect() and
258 * pwmd_tcp_connect_async().
260 static gpg_error_t
init_tcp_conn(pwmd_tcp_conn_t
**dst
, const char *host
,
261 int port
, const char *identity
, const char *user
, const char *hosts
,
264 pwmd_tcp_conn_t
*conn
;
269 return GPG_ERR_INV_ARG
;
272 if (!host
|| !identity
|| !user
|| !hosts
)
273 return GPG_ERR_INV_ARG
;
276 conn
= xcalloc(1, sizeof(pwmd_tcp_conn_t
));
279 return gpg_error_from_errno(ENOMEM
);
281 conn
->port
= port
== -1 ? 22 : port
;
282 conn
->host
= xstrdup(host
);
285 rc
= gpg_error_from_errno(ENOMEM
);
290 conn
->identity
= xstrdup(identity
);
292 if (!conn
->identity
) {
293 rc
= gpg_error_from_errno(ENOMEM
);
297 conn
->identity_pub
= xmalloc(strlen(conn
->identity
)+5);
299 if (!conn
->identity_pub
) {
300 rc
= gpg_error_from_errno(ENOMEM
);
304 sprintf(conn
->identity_pub
, "%s.pub", conn
->identity
);
305 conn
->username
= xstrdup(user
);
307 if (!conn
->username
) {
308 rc
= gpg_error_from_errno(ENOMEM
);
312 conn
->known_hosts
= xstrdup(hosts
);
314 if (!conn
->known_hosts
) {
315 rc
= gpg_error_from_errno(ENOMEM
);
328 static gpg_error_t
do_connect(pwm_t
*pwm
, int prot
, void *addr
)
330 struct sockaddr_in their_addr
;
332 pwm
->tcp_conn
->fd
= socket(prot
, SOCK_STREAM
, 0);
334 if (pwm
->tcp_conn
->fd
== -1)
335 return gpg_error_from_syserror();
337 if (pwm
->tcp_conn
->async
)
338 fcntl(pwm
->tcp_conn
->fd
, F_SETFL
, O_NONBLOCK
);
340 pwm
->cmd
= ASYNC_CMD_CONNECT
;
341 their_addr
.sin_family
= prot
;
342 their_addr
.sin_port
= htons(pwm
->tcp_conn
->port
);
343 their_addr
.sin_addr
= *((struct in_addr
*)addr
);
344 memset(their_addr
.sin_zero
, '\0', sizeof their_addr
.sin_zero
);
347 if (pth_connect(pwm
->tcp_conn
->fd
, (struct sockaddr
*)&their_addr
,
348 sizeof(their_addr
)) == -1)
350 if (connect(pwm
->tcp_conn
->fd
, (struct sockaddr
*)&their_addr
,
351 sizeof(their_addr
)) == -1)
353 return gpg_error_from_syserror();
358 static gpg_error_t
ares_error_to_pwmd(int status
)
360 if (status
!= ARES_SUCCESS
)
361 warnx("%s", ares_strerror(status
));
367 return GPG_ERR_UNKNOWN_HOST
;
369 return GPG_ERR_EHOSTDOWN
;
371 return GPG_ERR_TIMEOUT
;
373 return gpg_error_from_errno(ENOMEM
);
374 case ARES_ECONNREFUSED
:
375 return GPG_ERR_ECONNREFUSED
;
378 return GPG_ERR_EHOSTUNREACH
;
384 static void dns_resolve_cb(void *arg
, int status
, int timeouts
,
385 unsigned char *abuf
, int alen
)
391 if (status
== ARES_EDESTRUCTION
)
394 if (status
!= ARES_SUCCESS
) {
395 pwm
->tcp_conn
->rc
= ares_error_to_pwmd(status
);
399 //FIXME localhost. works with ipv4. maybe local system config error
400 /* Check for an IPv6 address first. */
401 rc
= ares_parse_a_reply(abuf
, alen
, &he
, NULL
, NULL
);
403 if (rc
!= ARES_SUCCESS
) {
404 if (rc
!= ARES_ENODATA
) {
405 pwm
->tcp_conn
->rc
= ares_error_to_pwmd(status
);
409 rc
= ares_parse_aaaa_reply(abuf
, alen
, &he
, NULL
, NULL
);
411 if (rc
!= ARES_SUCCESS
) {
412 pwm
->tcp_conn
->rc
= ares_error_to_pwmd(status
);
417 pwm
->tcp_conn
->he
= he
;
418 pwm
->tcp_conn
->rc
= do_connect(pwm
, he
->h_addrtype
, he
->h_addr
);
421 pwm_t
*_do_pwmd_tcp_connect_async(const char *host
, int port
,
422 const char *identity
, const char *user
, const char *known_hosts
,
423 gpg_error_t
*rc
, pwmd_async_cmd_t which
)
425 pwmd_tcp_conn_t
*conn
;
428 *rc
= init_tcp_conn(&conn
, host
, port
, identity
, user
, known_hosts
,
429 which
== ASYNC_CMD_HOSTKEY
? 1 : 0);
434 if ((pwm
= (pwm_t
*)xcalloc(1, sizeof(pwm_t
))) == NULL
) {
435 *rc
= gpg_error_from_syserror();
441 pwm
->tcp_conn
= conn
;
442 pwm
->tcp_conn
->cmd
= which
;
444 if (pwm
->tcp_conn
->cmd
== ASYNC_CMD_HOSTKEY
)
445 pwm
->tcp_conn
->get_only
= 1;
447 pwm
->cmd
= ASYNC_CMD_DNS
;
448 pwm
->state
= ASYNC_PROCESS
;
449 ares_init(&pwm
->tcp_conn
->chan
);
450 ares_query(pwm
->tcp_conn
->chan
, pwm
->tcp_conn
->host
, ns_c_any
, ns_t_any
,
451 dns_resolve_cb
, pwm
);
455 pwm_t
*pwmd_tcp_connect_async(const char *host
, int port
, const char *identity
,
456 const char *user
, const char *known_hosts
, gpg_error_t
*rc
)
458 return _do_pwmd_tcp_connect_async(host
, port
, identity
, user
, known_hosts
,
459 rc
, ASYNC_CMD_CONNECT
);
462 void *_ssh_malloc(size_t size
, void **data
)
464 return xmalloc(size
);
467 void _ssh_free(void *ptr
, void **data
)
472 void *_ssh_realloc(void *ptr
, size_t size
, void **data
)
474 return xrealloc(ptr
, size
);
477 static char *to_hex(const char *str
, size_t slen
)
480 char *buf
= xmalloc(slen
*2+1);
485 for (i
= 0, buf
[0] = 0; i
< slen
; i
++) {
488 sprintf(tmp
, "%02x", (unsigned char)str
[i
]);
495 static int verify_host_key(pwm_t
*pwm
)
497 FILE *fp
= fopen(pwm
->tcp_conn
->known_hosts
, "r");
503 buf
= xmalloc(LINE_MAX
);
508 while ((p
= fgets(buf
, LINE_MAX
, fp
))) {
509 if (*p
== '#' || isspace(*p
))
512 if (p
[strlen(p
)-1] == '\n')
515 if (!strcmp(buf
, pwm
->tcp_conn
->hostkey
))
532 static gpg_error_t
authenticate_ssh(pwm_t
*pwm
)
534 const char *fp
= libssh2_hostkey_hash(pwm
->tcp_conn
->session
,
535 LIBSSH2_HOSTKEY_HASH_SHA1
);
538 pwm
->tcp_conn
->hostkey
= to_hex(fp
, 20);
540 if (!pwm
->tcp_conn
->hostkey
)
541 return gpg_error_from_errno(ENOMEM
);
543 if (pwm
->tcp_conn
->get_only
)
546 if (!fp
|| verify_host_key(pwm
))
547 return GPG_ERR_CHECKSUM
;
549 userauth
= libssh2_userauth_list(pwm
->tcp_conn
->session
,
550 pwm
->tcp_conn
->username
, strlen(pwm
->tcp_conn
->username
));
552 if (!userauth
|| !strstr(userauth
, "publickey"))
553 return GPG_ERR_BAD_PIN_METHOD
;
555 if (libssh2_userauth_publickey_fromfile(pwm
->tcp_conn
->session
,
556 pwm
->tcp_conn
->username
, pwm
->tcp_conn
->identity_pub
,
557 pwm
->tcp_conn
->identity
, NULL
))
558 return GPG_ERR_BAD_SECKEY
;
563 static pwm_t
*setup_context(pwm_t
*pwm
, gpg_error_t
*rc
)
565 assuan_context_t ctx
;
566 struct assuan_io_hooks io_hooks
= {read_hook
, write_hook
};
568 pwm
->tcp_conn
->session
= libssh2_session_init_ex(_ssh_malloc
, _ssh_free
,
571 if (!pwm
->tcp_conn
->session
) {
572 *rc
= gpg_error_from_errno(ENOMEM
);
576 if (libssh2_session_startup(pwm
->tcp_conn
->session
, pwm
->tcp_conn
->fd
)) {
577 *rc
= GPG_ERR_ASSUAN_SERVER_FAULT
;
581 *rc
= authenticate_ssh(pwm
);
586 /* pwmd_get_hostkey(). */
587 if (pwm
->tcp_conn
->get_only
) {
588 pwm
->result
= xstrdup(pwm
->tcp_conn
->hostkey
);
591 *rc
= gpg_error_from_errno(ENOMEM
);
598 pwm
->tcp_conn
->channel
= libssh2_channel_open_session(pwm
->tcp_conn
->session
);
600 if (!pwm
->tcp_conn
->channel
) {
601 *rc
= GPG_ERR_ASSUAN_SERVER_FAULT
;
605 if (libssh2_channel_shell(pwm
->tcp_conn
->channel
)) {
606 *rc
= GPG_ERR_ASSUAN_SERVER_FAULT
;
610 assuan_set_io_hooks(&io_hooks
);
611 *rc
= assuan_socket_connect_fd(&ctx
, pwm
->tcp_conn
->fd
, 0, pwm
);
616 assuan_set_finish_handler(ctx
, _ssh_assuan_deinit
);
617 return _socket_connect_finalize(pwm
, ctx
);
620 if (!pwm
->tcp_conn
->async
)
626 static pwm_t
*_do_pwmd_tcp_connect(const char *host
, int port
,
627 const char *identity
, const char *user
, const char *known_hosts
,
628 gpg_error_t
*rc
, int get
)
631 pwmd_tcp_conn_t
*conn
;
633 *rc
= init_tcp_conn(&conn
, host
, port
, identity
, user
, known_hosts
, get
);
638 if ((pwm
= (pwm_t
*)xcalloc(1, sizeof(pwm_t
))) == NULL
) {
639 *rc
= gpg_error_from_errno(ENOMEM
);
643 pwm
->tcp_conn
= conn
;
644 pwm
->tcp_conn
->get_only
= get
;
645 pwm
->cmd
= ASYNC_CMD_DNS
;
646 ares_init(&pwm
->tcp_conn
->chan
);
647 ares_query(pwm
->tcp_conn
->chan
, pwm
->tcp_conn
->host
, ns_c_any
, ns_t_any
,
648 dns_resolve_cb
, pwm
);
650 /* dns_resolve_cb() may have already been called. */
651 if (pwm
->tcp_conn
->rc
) {
652 *rc
= pwm
->tcp_conn
->rc
;
657 * Fake a blocking DNS lookup. libcares does a better job than
667 n
= ares_fds(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
668 ares_timeout(pwm
->tcp_conn
->chan
, NULL
, &tv
);
670 n
= pth_select(n
, &rfds
, &wfds
, NULL
, &tv
);
672 n
= select(n
, &rfds
, &wfds
, NULL
, &tv
);
676 *rc
= gpg_error_from_syserror();
680 *rc
= GPG_ERR_TIMEOUT
;
684 ares_process(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
686 if (pwm
->tcp_conn
->rc
)
688 } while (pwm
->cmd
== ASYNC_CMD_DNS
);
690 if (pwm
->tcp_conn
->rc
) {
691 *rc
= pwm
->tcp_conn
->rc
;
695 return setup_context(pwm
, rc
);
702 pwm_t
*pwmd_tcp_connect(const char *host
, int port
, const char *identity
,
703 const char *user
, const char *known_hosts
, gpg_error_t
*rc
)
705 return _do_pwmd_tcp_connect(host
, port
, identity
, user
, known_hosts
, rc
, 0);
708 /* Must free the result with pwmd_free_result(). */
709 char *pwmd_get_hostkey(const char *host
, int port
, gpg_error_t
*rc
)
714 pwm
= _do_pwmd_tcp_connect(host
, port
, NULL
, NULL
, NULL
, rc
, 1);
719 hostkey
= xstrdup(pwm
->tcp_conn
->hostkey
);
722 *rc
= gpg_error_from_errno(ENOMEM
);
728 pwm_t
*pwmd_get_hostkey_async(const char *host
, int port
, gpg_error_t
*rc
)
730 return _do_pwmd_tcp_connect_async(host
, port
, NULL
, NULL
, NULL
, rc
,
735 pwm_t
*pwmd_connect(const char *path
, gpg_error_t
*rc
)
738 char *socketpath
= NULL
;
740 assuan_context_t ctx
;
743 pw
= getpwuid(getuid());
744 socketpath
= (char *)xmalloc(strlen(pw
->pw_dir
) + strlen("/.pwmd/socket") + 1);
745 sprintf(socketpath
, "%s/.pwmd/socket", pw
->pw_dir
);
748 socketpath
= xstrdup(path
);
750 *rc
= assuan_socket_connect_ext(&ctx
, socketpath
, -1, 0);
756 if ((pwm
= (pwm_t
*)xcalloc(1, sizeof(pwm_t
))) == NULL
) {
757 *rc
= gpg_error_from_syserror();
761 return _socket_connect_finalize(pwm
, ctx
);
764 gpg_error_t
pwmd_pending_line(pwm_t
*pwm
, char **line
, size_t *len
)
767 return GPG_ERR_INV_ARG
;
769 if (assuan_pending_line(pwm
->ctx
))
770 return assuan_read_line(pwm
->ctx
, line
, len
);
772 return GPG_ERR_NO_DATA
;
775 void pwmd_close(pwm_t
*pwm
)
781 assuan_disconnect(pwm
->ctx
);
784 xfree(pwm
->password
);
795 if (pwm
->pinentry_tty
)
796 xfree(pwm
->pinentry_tty
);
798 if (pwm
->pinentry_display
)
799 xfree(pwm
->pinentry_display
);
801 if (pwm
->pinentry_term
)
802 xfree(pwm
->pinentry_term
);
808 xfree(pwm
->lcmessages
);
811 xfree(pwm
->filename
);
818 free_tcp_conn(pwm
->tcp_conn
);
824 static int mem_realloc_cb(void *data
, const void *buffer
, size_t len
)
826 membuf_t
*mem
= (membuf_t
*)data
;
832 if ((p
= xrealloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
836 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
841 void pwmd_free_result(void *data
)
846 static int _inquire_cb(void *data
, const char *keyword
)
848 pwm_t
*pwm
= (pwm_t
*)data
;
850 int flags
= fcntl(pwm
->fd
, F_GETFL
);
852 /* Shouldn't get this far without a callback. */
853 if (!pwm
->inquire_func
)
854 return GPG_ERR_INV_ARG
;
857 * Since the socket file descriptor is probably set to non-blocking, set to
858 * blocking to prevent GPG_ERR_EAGAIN errors. This should be fixes when
859 * asynchronous INQUIRE is supported by either libassuan or a later
862 fcntl(pwm
->fd
, F_SETFL
, 0);
869 rc
= pwm
->inquire_func(pwm
->inquire_data
, keyword
, rc
, &result
, &len
);
870 rc
= gpg_err_code(rc
);
872 if (rc
== GPG_ERR_EOF
|| !rc
) {
873 if (len
<= 0 || !result
|| !*result
) {
878 arc
= assuan_send_data(pwm
->ctx
, result
, len
);
880 if (rc
== GPG_ERR_EOF
) {
891 fcntl(pwm
->fd
, F_SETFL
, flags
);
895 gpg_error_t
pwmd_finalize(pwm_t
*pwm
)
897 if (!pwm
|| pwm
->cmd
== ASYNC_CMD_NONE
|| pwm
->state
!= ASYNC_DONE
)
898 return GPG_ERR_INV_ARG
;
900 pwm
->state
= ASYNC_INIT
;
901 pwm
->cmd
= ASYNC_CMD_NONE
;
904 if (pwm
->cmd
== ASYNC_CMD_CONNECT
|| pwm
->cmd
== ASYNC_CMD_DNS
) {
905 gpg_error_t rc
= pwm
->tcp_conn
->rc
;
912 /* pwm is no longer a valid handle. */
921 return GPG_ERR_INV_ARG
;
925 pwm
->is_open_cmd
= 0;
930 static gpg_error_t
do_nb_command(pwm_t
*pwm
, const char *cmd
, const char *arg
)
934 size_t len
= strlen(cmd
) + 2;
936 len
+= arg
? strlen(arg
) : 0;
938 if (pwm
->state
!= ASYNC_INIT
)
939 return GPG_ERR_INV_STATE
;
941 buf
= (char *)xmalloc(len
);
944 rc
= gpg_error_from_errno(ENOMEM
);
948 snprintf(buf
, len
, "%s %s", cmd
, arg
? arg
: "");
949 rc
= assuan_write_line(pwm
->ctx
, buf
);
953 pwm
->state
= ASYNC_PROCESS
;
959 gpg_error_t
pwmd_open_async(pwm_t
*pwm
, const char *filename
)
961 if (!pwm
|| !filename
)
962 return GPG_ERR_INV_ARG
;
964 /* For pinentry retries. */
965 if (!pwm
->is_open_cmd
) {
967 xfree(pwm
->filename
);
969 pwm
->filename
= xstrdup(filename
);
972 pwm
->is_open_cmd
= 1;
973 pwm
->cmd
= ASYNC_CMD_OPEN
;
974 return do_nb_command(pwm
, "OPEN", filename
);
977 gpg_error_t
pwmd_save_async(pwm_t
*pwm
)
980 return GPG_ERR_INV_ARG
;
982 pwm
->cmd
= ASYNC_CMD_SAVE
;
983 return do_nb_command(pwm
, "SAVE", NULL
);
986 static gpg_error_t
parse_assuan_line(pwm_t
*pwm
)
992 rc
= assuan_read_line(pwm
->ctx
, &line
, &len
);
995 if (line
[0] == 'O' && line
[1] == 'K' &&
996 (line
[2] == 0 || line
[2] == ' ')) {
997 pwm
->state
= ASYNC_DONE
;
999 else if (line
[0] == '#') {
1001 else if (line
[0] == 'S' && (line
[1] == 0 || line
[1] == ' ')) {
1002 if (pwm
->status_func
) {
1003 pwm
->status_func(pwm
->status_data
,
1004 line
[1] == 0 ? line
+1 : line
+2);
1007 else if (line
[0] == 'E' && line
[1] == 'R' && line
[2] == 'R' &&
1008 (line
[3] == 0 || line
[3] == ' ')) {
1011 pwm
->state
= ASYNC_DONE
;
1018 gpg_error_t
pwmd_get_result(pwm_t
*pwm
, const char **result
)
1020 if (!pwm
|| !result
)
1021 return GPG_ERR_INV_ARG
;
1023 if (pwm
->state
!= ASYNC_DONE
)
1024 return GPG_ERR_INV_STATE
;
1027 return GPG_ERR_NO_DATA
;
1029 *result
= pwm
->result
;
1033 static gpg_error_t
assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
1034 char **result
, const char *cmd
);
1035 pwmd_async_t
pwmd_process(pwm_t
*pwm
, gpg_error_t
*rc
)
1039 struct timeval tv
= {0, 0};
1044 *rc
= GPG_ERR_INV_ARG
;
1049 if (pwm
->cmd
== ASYNC_CMD_DNS
) {
1052 if (pwm
->tcp_conn
->rc
) {
1053 *rc
= pwm
->tcp_conn
->rc
;
1054 close(pwm
->tcp_conn
->fd
);
1055 pwm
->state
= ASYNC_DONE
;
1061 n
= ares_fds(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
1063 /* Shouldn't happen. */
1067 n
= select(n
, &rfds
, &wfds
, NULL
, &tv
);
1070 ares_process(pwm
->tcp_conn
->chan
, &rfds
, &wfds
);
1074 else if (pwm
->cmd
== ASYNC_CMD_CONNECT
) {
1075 if (pwm
->tcp_conn
->rc
== GPG_ERR_EINPROGRESS
) {
1077 socklen_t len
= sizeof(int);
1080 FD_SET(pwm
->tcp_conn
->fd
, &fds
);
1081 n
= select(pwm
->tcp_conn
->fd
+1, NULL
, &fds
, NULL
, &tv
);
1083 if (!n
|| !FD_ISSET(pwm
->tcp_conn
->fd
, &fds
))
1086 *rc
= gpg_error_from_syserror();
1087 close(pwm
->tcp_conn
->fd
);
1088 pwm
->state
= ASYNC_DONE
;
1092 ret
= getsockopt(pwm
->tcp_conn
->fd
, SOL_SOCKET
, SO_ERROR
, &n
, &len
);
1094 *rc
= ret
? gpg_error_from_syserror() : gpg_error_from_errno(n
);
1095 close(pwm
->tcp_conn
->fd
);
1096 pwm
->state
= ASYNC_DONE
;
1100 else if (pwm
->tcp_conn
->rc
) {
1101 *rc
= pwm
->tcp_conn
->rc
;
1102 close(pwm
->tcp_conn
->fd
);
1103 pwm
->state
= ASYNC_DONE
;
1107 fcntl(pwm
->tcp_conn
->fd
, F_SETFL
, 0);
1108 setup_context(pwm
, rc
);
1109 pwm
->state
= ASYNC_DONE
;
1115 *rc
= GPG_ERR_INV_ARG
;
1119 if (pwm
->state
== ASYNC_DONE
)
1122 /* When not in a command, this will let libassuan process status messages
1123 * by calling PWMD_OPTION_STATUS_FUNC. */
1124 if (pwm
->cmd
== ASYNC_CMD_NONE
) {
1125 *rc
= assuan_command(pwm
, pwm
->ctx
, NULL
, "NOP");
1129 /* This is for the non-blocking OPEN and SAVE commands. */
1131 FD_SET(pwm
->fd
, &fds
);
1133 n
= pth_select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
1135 n
= select(pwm
->fd
+1, &fds
, NULL
, NULL
, &tv
);
1139 if (FD_ISSET(pwm
->fd
, &fds
))
1140 *rc
= parse_assuan_line(pwm
);
1143 while (!*rc
&& assuan_pending_line(pwm
->ctx
))
1144 *rc
= parse_assuan_line(pwm
);
1146 /* For pinentry retries. */
1147 if (pwm
->is_open_cmd
&& gpg_err_code(*rc
) == EPWMD_BADKEY
&&
1148 ++pwm
->ntries
< pwm
->pinentry_tries
) {
1149 pwm
->state
= ASYNC_INIT
;
1150 *rc
= pwmd_open_async(pwm
, pwm
->filename
);
1156 static gpg_error_t
assuan_command(pwm_t
*pwm
, assuan_context_t ctx
,
1157 char **result
, const char *cmd
)
1165 rc
= assuan_transact(ctx
, cmd
, mem_realloc_cb
, &data
, _inquire_cb
, pwm
,
1166 pwm
->status_func
, pwm
->status_data
);
1176 mem_realloc_cb(&data
, "", 1);
1180 rc
= GPG_ERR_INV_ARG
;
1183 *result
= (char *)data
.buf
;
1187 return gpg_err_code(rc
);
1190 gpg_error_t
pwmd_inquire(pwm_t
*pwm
, const char *cmd
, pwmd_inquire_fn fn
,
1193 if (!pwm
|| !cmd
|| !fn
)
1194 return GPG_ERR_INV_ARG
;
1196 pwm
->inquire_func
= fn
;
1197 pwm
->inquire_data
= data
;
1198 return assuan_command(pwm
, pwm
->ctx
, NULL
, cmd
);
1201 gpg_error_t
pwmd_terminate_pinentry(pwm_t
*pwm
)
1203 #ifndef WITH_PINENTRY
1204 return GPG_ERR_NOT_IMPLEMENTED
;
1206 pid_t pid
= pwm
->pid
;
1210 if (!pwm
|| pid
== -1)
1211 return GPG_ERR_INV_ARG
;
1213 if (kill(pid
, 0) == 0) {
1214 if (kill(pid
, SIGTERM
) == -1) {
1215 if (kill(pid
, SIGKILL
) == -1)
1216 return gpg_error_from_errno(errno
);
1219 pwm
->pin_error
= GPG_ERR_TIMEOUT
;
1222 return gpg_error_from_errno(errno
);
1228 #ifdef WITH_PINENTRY
1229 static gpg_error_t
set_pinentry_strings(pwm_t
*pwm
, int which
)
1232 char tmp
[ASSUAN_LINELENGTH
];
1236 pwm
->title
= xstrdup(N_("LibPWMD"));
1239 pwm
->prompt
= xstrdup(N_("Passphrase:"));
1241 if (!pwm
->desc
&& !which
)
1242 pwm
->desc
= xstrdup(N_("Enter a passphrase."));
1245 snprintf(tmp
, sizeof(tmp
), "SETERROR %s", N_("Invalid passphrase, please try again."));
1248 else if (which
== 2) {
1249 snprintf(tmp
, sizeof(tmp
), "SETERROR %s", N_("Please type the passphrase again for confirmation."));
1253 buf
= (char *)xmalloc(strlen("SETERROR ") + strlen(pwm
->desc
) + 1);
1254 sprintf(buf
, "SETERROR %s", pwm
->desc
);
1257 error
= pinentry_command(pwm
, NULL
, buf
);
1263 buf
= (char *)xmalloc(strlen("SETPROMPT ") + strlen(pwm
->prompt
) + 1);
1264 sprintf(buf
, "SETPROMPT %s", pwm
->prompt
);
1265 error
= pinentry_command(pwm
, NULL
, buf
);
1271 buf
= (char *)xmalloc(strlen("SETDESC ") + strlen(pwm
->title
) + 1);
1272 sprintf(buf
, "SETDESC %s", pwm
->title
);
1273 error
= pinentry_command(pwm
, NULL
, buf
);
1278 static void update_pinentry_settings(pwm_t
*pwm
)
1282 struct passwd
*pw
= getpwuid(getuid());
1285 snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", pw
->pw_dir
);
1287 if ((fp
= fopen(buf
, "r")) == NULL
)
1290 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
1291 char name
[32], val
[256];
1293 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, val
) != 2)
1296 if (strcasecmp(name
, "TTYNAME") == 0) {
1297 xfree(pwm
->pinentry_tty
);
1298 pwm
->pinentry_tty
= xstrdup(val
);
1300 else if (strcasecmp(name
, "TTYTYPE") == 0) {
1301 xfree(pwm
->pinentry_term
);
1302 pwm
->pinentry_term
= xstrdup(val
);
1304 else if (strcasecmp(name
, "DISPLAY") == 0) {
1305 xfree(pwm
->pinentry_display
);
1306 pwm
->pinentry_display
= xstrdup(val
);
1308 else if (strcasecmp(name
, "PATH") == 0) {
1309 xfree(pwm
->pinentry_path
);
1310 pwm
->pinentry_path
= xstrdup(val
);
1317 static gpg_error_t
launch_pinentry(pwm_t
*pwm
)
1320 assuan_context_t ctx
;
1321 int child_list
[] = {-1};
1322 char *display
= getenv("DISPLAY");
1323 const char *argv
[10];
1324 const char **p
= argv
;
1325 int have_display
= 0;
1328 update_pinentry_settings(pwm
);
1330 if (pwm
->pinentry_display
|| display
)
1333 tty
= pwm
->pinentry_tty
? pwm
->pinentry_tty
: ttyname(STDOUT_FILENO
);
1336 return gpg_error_from_errno(errno
);
1339 if (!have_display
&& !tty
)
1340 return GPG_ERR_ENOTTY
;
1343 *p
++ = have_display
? "--display" : "--ttyname";
1344 *p
++ = have_display
? pwm
->pinentry_display
? pwm
->pinentry_display
: display
: tty
;
1347 *p
++ = "--lc-ctype";
1348 *p
++ = pwm
->lcctype
;
1351 if (pwm
->lcmessages
) {
1352 *p
++ = "--lc-messages";
1353 *p
++ = pwm
->lcmessages
;
1358 if (!have_display
) {
1360 *p
++ = pwm
->pinentry_term
? pwm
->pinentry_term
: getenv("TERM");
1364 rc
= assuan_pipe_connect(&ctx
, pwm
->pinentry_path
? pwm
->pinentry_path
: PINENTRY_PATH
, argv
, child_list
);
1369 pwm
->pid
= assuan_get_pid(ctx
);
1371 return set_pinentry_strings(pwm
, 0);
1374 static gpg_error_t
pinentry_command(pwm_t
*pwm
, char **result
, const char *cmd
)
1379 n
= launch_pinentry(pwm
);
1385 return assuan_command(pwm
, pwm
->pctx
, result
, cmd
);
1388 static void pinentry_disconnect(pwm_t
*pwm
)
1391 assuan_disconnect(pwm
->pctx
);
1398 * Only called from a child process.
1400 static void catchsig(int sig
)
1404 if (gelapsed
++ >= gtimeout
) {
1405 global_error
= pwmd_terminate_pinentry(gpwm
);
1408 global_error
= GPG_ERR_TIMEOUT
;
1422 * Borrowed from libassuan.
1424 static char *percent_escape(const char *atext
)
1426 const unsigned char *s
;
1427 int len
= strlen(atext
) * 3 + 1;
1428 char *buf
= (char *)xmalloc(len
), *p
= buf
;
1433 for (s
=(const unsigned char *)atext
; *s
; s
++) {
1435 sprintf (p
, "%%%02X", *s
);
1446 static gpg_error_t
send_command(pwm_t
*pwm
, char **result
, const char *cmd
)
1449 return GPG_ERR_INV_ARG
;
1451 return assuan_command(pwm
, pwm
->ctx
, result
, cmd
);
1454 gpg_error_t
pwmd_command_ap(pwm_t
*pwm
, char **result
, const char *cmd
,
1462 return GPG_ERR_INV_ARG
;
1465 * C99 allows the dst pointer to be null which will calculate the length
1466 * of the would-be result and return it.
1468 len
= vsnprintf(NULL
, 0, cmd
, ap
)+1;
1469 buf
= (char *)xmalloc(len
);
1470 len
= vsnprintf(buf
, len
, cmd
, ap
);
1471 error
= send_command(pwm
, result
, buf
);
1477 * Avoid sending the BYE command here. libassuan will close the file
1478 * descriptor and release the assuan context. Use pwmd_close() instead.
1480 gpg_error_t
pwmd_command(pwm_t
*pwm
, char **result
, const char *cmd
, ...)
1486 return GPG_ERR_INV_ARG
;
1490 error
= pwmd_command_ap(pwm
, result
, cmd
, ap
);
1495 #ifdef WITH_PINENTRY
1496 static gpg_error_t
do_getpin(pwm_t
*pwm
, char **result
)
1499 signal(SIGALRM
, catchsig
);
1504 return pinentry_command(pwm
, result
, "GETPIN");
1507 static gpg_error_t
getpin(pwm_t
*pwm
, char **result
, int *try_n
, int which
)
1509 int pin_try
= *try_n
;
1515 if (pin_try
== -1) {
1516 error
= set_pinentry_strings(pwm
, which
);
1519 pinentry_disconnect(pwm
);
1524 if (pwm
->pinentry_tries
-1 != pin_try
) {
1525 error
= set_pinentry_strings(pwm
, 1);
1528 pinentry_disconnect(pwm
);
1534 error
= do_getpin(pwm
, result
);
1537 * Since there was input cancel any timeout setting.
1542 if (error
== GPG_ERR_CANCELED
)
1543 return GPG_ERR_CANCELED
;
1545 if (pin_try
!= -1 && pin_try
--)
1549 pinentry_disconnect(pwm
);
1559 gpg_error_t
pwmd_open_nb_finalize(pwm_t
*pwm
, pwmd_nb_status_t
*pw
)
1563 #ifndef WITH_PINENTRY
1564 return GPG_ERR_NOT_IMPLEMENTED
;
1567 if (!pwm
|| !pw
|| !pw
->filename
[0])
1568 return GPG_ERR_INV_ARG
;
1578 xfree(pwm
->filename
);
1580 pwm
->filename
= xstrdup(pw
->filename
);
1581 memset(pw
, 0, sizeof(pwmd_nb_status_t
));
1585 memset(pw
, 0, sizeof(pwmd_nb_status_t
));
1589 static gpg_error_t
do_open_command(pwm_t
*pwm
, const char *filename
, char *password
)
1591 char buf
[ASSUAN_LINELENGTH
];
1593 char *result
= NULL
;
1595 snprintf(buf
, sizeof(buf
), "OPEN %s %s", filename
, password
? password
: "");
1596 error
= send_command(pwm
, &result
, buf
);
1597 memset(buf
, 0, sizeof(buf
));
1599 if (error
&& result
)
1605 static int do_pwmd_open(pwm_t
*pwm
, gpg_error_t
*error
, const char *filename
,
1606 int nb
, int timeout
)
1608 char *result
= NULL
;
1609 char *password
= NULL
;
1610 char path
[PATH_MAX
];
1611 #ifdef WITH_PINENTRY
1615 if (!pwm
|| !filename
|| !*filename
) {
1616 *error
= GPG_ERR_INV_ARG
;
1620 #ifdef WITH_PINENTRY
1621 pin_try
= pwm
->pinentry_tries
- 1;
1625 * Avoid calling pinentry if the password is cached on the server or if
1626 * this is a new file.
1628 *error
= pwmd_command(pwm
, &result
, "GETCONFIG data_directory");
1633 snprintf(path
, sizeof(path
), "%s/%s", result
, filename
);
1634 pwmd_free_result(result
);
1636 if (access(path
, R_OK
) == -1) {
1637 if (errno
== ENOENT
)
1641 *error
= pwmd_command(pwm
, &result
, "ISCACHED %s", filename
);
1643 if (*error
== EPWMD_CACHE_NOT_FOUND
) {
1644 if (pwm
->passfunc
) {
1645 password
= pwm
->passfunc(pwm
, pwm
->passdata
);
1649 #ifdef WITH_PINENTRY
1651 * Get the password from pinentry.
1653 if (pwm
->use_pinentry
) {
1655 * Nonblocking is wanted. fork() then return a file descriptor
1656 * that the client can use to read() from.
1661 pwmd_nb_status_t pw
;
1663 if (pipe(p
) == -1) {
1664 *error
= gpg_error_from_syserror();
1677 strncpy(pw
.filename
, filename
, sizeof(pw
.filename
));
1678 pw
.filename
[sizeof(pw
.filename
)-1] = 0;
1688 *error
= getpin(pwm
, &password
, &pin_try
, 0);
1693 pinentry_disconnect(pwm
);
1695 if (gtimeout
&& gelapsed
>= gtimeout
)
1696 *error
= GPG_ERR_TIMEOUT
;
1700 pth_write(p
[1], &pw
, sizeof(pw
));
1702 write(p
[1], &pw
, sizeof(pw
));
1709 * Don't count the time it takes to open the file
1710 * which may have many iterations.
1712 signal(SIGALRM
, SIG_DFL
);
1713 *error
= do_open_command(pwm
, filename
, password
);
1716 signal(SIGALRM
, catchsig
);
1718 if (pwm
->pctx
&& *error
== EPWMD_BADKEY
) {
1720 goto getpin_nb_again
;
1722 goto getpin_nb_fail
;
1725 pinentry_disconnect(pwm
);
1728 pth_write(p
[1], &pw
, sizeof(pw
));
1730 write(p
[1], &pw
, sizeof(pw
));
1736 *error
= gpg_error_from_syserror();
1752 * Not using pinentry and the file was not found
1755 password
= pwm
->password
;
1756 #ifdef WITH_PINENTRY
1764 *error
= do_open_command(pwm
, filename
, password
);
1767 * Keep the user defined password set with pwmd_setopt(). The password may
1768 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1770 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
1773 #ifdef WITH_PINENTRY
1774 if (*error
== EPWMD_BADKEY
) {
1775 if (pin_try
-- > 0 && !nb
) {
1776 *error
= pwmd_command(pwm
, &result
, "OPTION TITLE=%s",
1777 N_("Invalid passphrase, please try again."));
1786 pinentry_disconnect(pwm
);
1794 xfree(pwm
->filename
);
1796 pwm
->filename
= xstrdup(filename
);
1800 * The file is cached or the file is a new file.
1803 return *error
? -1 : -2;
1805 return *error
? 1 : 0;
1808 gpg_error_t
pwmd_open(pwm_t
*pwm
, const char *filename
)
1812 do_pwmd_open(pwm
, &error
, filename
, 0, 0);
1816 int pwmd_open_nb(pwm_t
*pwm
, gpg_error_t
*error
, const char *filename
,
1819 #ifndef WITH_PINENTRY
1820 *error
= GPG_ERR_NOT_IMPLEMENTED
;
1823 return do_pwmd_open(pwm
, error
, filename
, 1, timeout
);
1827 #ifdef WITH_PINENTRY
1828 static gpg_error_t
do_save_getpin(pwm_t
*pwm
, char **password
)
1832 char *result
= NULL
;
1836 error
= getpin(pwm
, &result
, &pin_try
, confirm
? 2 : 0);
1840 pinentry_disconnect(pwm
);
1853 if (strcmp(*password
, result
)) {
1856 pinentry_disconnect(pwm
);
1857 error
= EPWMD_BADKEY
;
1862 pinentry_disconnect(pwm
);
1867 static gpg_error_t
do_save_command(pwm_t
*pwm
, char *password
)
1869 char buf
[ASSUAN_LINELENGTH
];
1871 char *result
= NULL
;
1873 snprintf(buf
, sizeof(buf
), "SAVE %s", password
? password
: "");
1874 error
= send_command(pwm
, &result
, buf
);
1875 memset(&buf
, 0, sizeof(buf
));
1877 if (error
&& result
)
1883 gpg_error_t
pwmd_save_nb_finalize(pwm_t
*pwm
, pwmd_nb_status_t
*pw
)
1887 #ifndef WITH_PINENTRY
1888 return GPG_ERR_NOT_IMPLEMENTED
;
1891 if (!pwm
|| !pw
|| !pw
->filename
[0])
1892 return GPG_ERR_INV_ARG
;
1896 memset(pw
, 0, sizeof(pwmd_nb_status_t
));
1900 static int do_pwmd_save(pwm_t
*pwm
, gpg_error_t
*error
, int nb
)
1902 char *result
= NULL
;
1903 char *password
= NULL
;
1906 *error
= GPG_ERR_INV_ARG
;
1910 if (pwm
->use_pinentry
|| pwm
->passfunc
) {
1911 *error
= pwmd_command(pwm
, &result
, "ISCACHED %s", pwm
->filename
);
1913 if (*error
== EPWMD_CACHE_NOT_FOUND
) {
1915 password
= (*pwm
->passfunc
)(pwm
, pwm
->passdata
);
1916 #ifdef WITH_PINENTRY
1917 else if (pwm
->use_pinentry
) {
1921 pwmd_nb_status_t pw
;
1923 if (pipe(p
) == -1) {
1924 *error
= gpg_error_from_syserror();
1937 strncpy(pw
.filename
, pwm
->filename
, sizeof(pw
.filename
));
1938 pw
.filename
[sizeof(pw
.filename
)-1] = 0;
1943 *error
= do_save_getpin(pwm
, &password
);
1944 } while (*error
== EPWMD_BADKEY
);
1948 pinentry_disconnect(pwm
);
1952 pth_write(p
[1], &pw
, sizeof(pw
));
1954 write(p
[1], &pw
, sizeof(pw
));
1960 *error
= do_save_command(pwm
, password
);
1961 pinentry_disconnect(pwm
);
1964 pth_write(p
[1], &pw
, sizeof(pw
));
1966 write(p
[1], &pw
, sizeof(pw
));
1972 *error
= gpg_error_from_syserror();
1985 *error
= do_save_getpin(pwm
, &password
);
1998 password
= pwm
->password
;
2000 *error
= do_save_command(pwm
, password
);
2002 if (!pwm
->passfunc
&& password
&& password
!= pwm
->password
)
2006 return *error
? -1 : -2;
2008 return *error
? 1 : 0;
2011 int pwmd_save_nb(pwm_t
*pwm
, gpg_error_t
*error
)
2013 #ifndef WITH_PINENTRY
2014 *error
= GPG_ERR_NOT_IMPLEMENTED
;
2017 return do_pwmd_save(pwm
, error
, 1);
2021 gpg_error_t
pwmd_save(pwm_t
*pwm
)
2025 do_pwmd_save(pwm
, &error
, 0);
2029 gpg_error_t
pwmd_setopt(pwm_t
*pwm
, pwmd_option_t opt
, ...)
2032 int n
= va_arg(ap
, int);
2035 gpg_error_t error
= 0;
2038 return GPG_ERR_INV_ARG
;
2043 case PWMD_OPTION_STATUS_FUNC
:
2044 pwm
->status_func
= va_arg(ap
, pwmd_status_fn
);
2046 case PWMD_OPTION_STATUS_DATA
:
2047 pwm
->status_data
= va_arg(ap
, void *);
2049 case PWMD_OPTION_PASSWORD_FUNC
:
2050 pwm
->passfunc
= va_arg(ap
, pwmd_password_fn
);
2052 case PWMD_OPTION_PASSWORD_DATA
:
2053 pwm
->passdata
= va_arg(ap
, void *);
2055 case PWMD_OPTION_PASSWORD
:
2056 arg1
= va_arg(ap
, char *);
2059 xfree(pwm
->password
);
2061 pwm
->password
= xstrdup(arg1
);
2063 case PWMD_OPTION_PINENTRY
:
2064 n
= va_arg(ap
, int);
2066 if (n
!= 0 && n
!= 1) {
2068 error
= GPG_ERR_INV_VALUE
;
2071 pwm
->use_pinentry
= n
;
2072 error
= pwmd_command(pwm
, &result
, "OPTION PINENTRY=%i",
2073 !pwm
->use_pinentry
);
2076 #ifdef WITH_PINENTRY
2077 case PWMD_OPTION_PINENTRY_TRIES
:
2078 n
= va_arg(ap
, int);
2082 error
= GPG_ERR_INV_VALUE
;
2085 pwm
->pinentry_tries
= n
;
2088 case PWMD_OPTION_PINENTRY_TIMEOUT
:
2089 n
= va_arg(ap
, int);
2093 error
= GPG_ERR_INV_VALUE
;
2096 pwm
->pinentry_timeout
= n
;
2098 if (!pwm
->use_pinentry
)
2099 error
= pwmd_command(pwm
, &result
, "OPTION TIMEOUT=%i",
2100 pwm
->pinentry_timeout
);
2102 case PWMD_OPTION_PINENTRY_PATH
:
2103 if (pwm
->pinentry_path
)
2104 xfree(pwm
->pinentry_path
);
2106 pwm
->pinentry_path
= xstrdup(va_arg(ap
, char *));
2108 if (!pwm
->use_pinentry
)
2109 error
= pwmd_command(pwm
, &result
, "OPTION PATH=%s",
2110 pwm
->pinentry_path
);
2112 case PWMD_OPTION_PINENTRY_TTY
:
2113 if (pwm
->pinentry_tty
)
2114 xfree(pwm
->pinentry_tty
);
2116 pwm
->pinentry_tty
= xstrdup(va_arg(ap
, char *));
2118 if (!pwm
->use_pinentry
)
2119 error
= pwmd_command(pwm
, &result
, "OPTION TTY=%s",
2122 case PWMD_OPTION_PINENTRY_DISPLAY
:
2123 if (pwm
->pinentry_display
)
2124 xfree(pwm
->pinentry_display
);
2126 pwm
->pinentry_display
= xstrdup(va_arg(ap
, char *));
2128 if (!pwm
->use_pinentry
)
2129 error
= pwmd_command(pwm
, &result
, "OPTION DISPLAY=%s",
2130 pwm
->pinentry_display
);
2132 case PWMD_OPTION_PINENTRY_TERM
:
2133 if (pwm
->pinentry_term
)
2134 xfree(pwm
->pinentry_term
);
2136 pwm
->pinentry_term
= xstrdup(va_arg(ap
, char *));
2138 if (!pwm
->use_pinentry
)
2139 error
= pwmd_command(pwm
, &result
, "OPTION TTYTYPE=%s",
2140 pwm
->pinentry_term
);
2142 case PWMD_OPTION_PINENTRY_TITLE
:
2146 pwm
->title
= percent_escape(va_arg(ap
, char *));
2148 if (!pwm
->use_pinentry
)
2149 error
= pwmd_command(pwm
, &result
, "OPTION TITLE=%s",
2152 case PWMD_OPTION_PINENTRY_PROMPT
:
2156 pwm
->prompt
= percent_escape(va_arg(ap
, char *));
2158 if (!pwm
->use_pinentry
)
2159 error
= pwmd_command(pwm
, &result
, "OPTION PROMPT=%s",
2162 case PWMD_OPTION_PINENTRY_DESC
:
2166 pwm
->desc
= percent_escape(va_arg(ap
, char *));
2168 if (!pwm
->use_pinentry
)
2169 error
= pwmd_command(pwm
, &result
, "OPTION DESC=%s",
2172 case PWMD_OPTION_PINENTRY_LC_CTYPE
:
2174 xfree(pwm
->lcctype
);
2176 pwm
->lcctype
= xstrdup(va_arg(ap
, char *));
2178 if (!pwm
->use_pinentry
)
2179 error
= pwmd_command(pwm
, &result
, "OPTION LC_CTYPE=%s",
2182 case PWMD_OPTION_PINENTRY_LC_MESSAGES
:
2183 if (pwm
->lcmessages
)
2184 xfree(pwm
->lcmessages
);
2186 pwm
->lcmessages
= xstrdup(va_arg(ap
, char *));
2188 if (!pwm
->use_pinentry
)
2189 error
= pwmd_command(pwm
, &result
, "OPTION LC_MESSAGES=%s",
2193 error
= GPG_ERR_NOT_IMPLEMENTED
;
2202 * Prevent requiring assuan.h when setting ctx. The ctx is really an
2203 * assuan_context_t *.
2205 gpg_error_t
pwmd_assuan_ctx(pwm_t
*pwm
, void *ctx
, int *fd
)
2208 return GPG_ERR_INV_ARG
;