Initialize libssh2. Now requires libssh2 1.2.5 or later.
[libpwmd.git] / src / libpwmd.c
blob9439163b46dd7d35fc48f8986b5ebc0b6ec27e1f
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <sys/wait.h>
32 #include <fcntl.h>
33 #include <pwd.h>
34 #include <time.h>
35 #include <sys/types.h>
36 #include <limits.h>
37 #include <sys/select.h>
38 #include <libpwmd.h>
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
44 #ifdef HAVE_ASSUAN_H
45 #include <assuan.h>
46 #endif
48 #include "mem.h"
49 #include "misc.h"
50 #include "types.h"
52 #ifdef WITH_PINENTRY
53 #include "pinentry.h"
54 #endif
56 #ifdef WITH_TCP
57 #include "ssh.h"
58 #endif
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)) {
70 switch (code) {
71 case GPG_ERR_USER_1:
72 return N_("No file is open");
73 case GPG_ERR_USER_2:
74 return N_("General LibXML error");
75 case GPG_ERR_USER_3:
76 return N_("File modified");
77 default:
78 return N_("Unknown error");
82 return NULL;
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);
96 if (p) {
97 snprintf(buf, size, "%s", p);
99 if (strlen(p) > size)
100 return ERANGE;
102 return 0;
105 return gpg_strerror_r(code, buf, size);
108 gpg_error_t pwmd_init()
110 static int initialized;
112 if (initialized)
113 return 0;
115 #ifndef MEM_DEBUG
116 _xmem_init();
117 #endif
118 #ifdef ENABLE_NLS
119 bindtextdomain("libpwmd", LOCALEDIR);
120 #endif
121 #ifdef WITH_TCP
122 libssh2_init(0);
123 #endif
124 gpg_err_init();
125 assuan_set_malloc_hooks(pwmd_malloc, pwmd_realloc, pwmd_free);
126 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
127 initialized = 1;
128 return 0;
131 gpg_error_t _connect_finalize(pwm_t *pwm)
133 int active[2];
134 int n = assuan_get_active_fds(pwm->ctx, 0, active, N_ARRAY(active));
135 gpg_error_t rc;
137 if (n <= 0)
138 return GPG_ERR_EBADFD;
140 pwm->fd = active[0];
141 #ifdef WITH_PINENTRY
142 pwm->pid = -1;
143 #endif
144 assuan_set_pointer(pwm->ctx, pwm);
146 #ifdef WITH_TCP
147 // Until X11 forwarding is supported, disable the remote pwmd pinentry.
148 if (pwm->tcp_conn) {
149 pwm->tcp_conn->state = SSH_NONE;
150 rc = pwmd_command(pwm, NULL, "SET ENABLE_PINENTRY=0");
152 if (rc)
153 return rc;
155 #endif
157 if (pwm->name) {
158 rc = pwmd_command(pwm, NULL, "SET NAME=%s", pwm->name);
160 if (rc)
161 return rc;
164 return 0;
167 static gpg_error_t _pwmd_connect_url(pwm_t *pwm, const char *url, int async)
169 char *p = (char *)url;
170 gpg_error_t rc;
172 if (!pwm)
173 return GPG_ERR_INV_ARG;
175 if (!p || !strncmp(p, "file://", 7) || !strncmp(p, "local://", 8)) {
176 if (p) {
177 if (!strncmp(p, "file://", 7))
178 p += 7;
179 else
180 p += 8;
183 goto connect_uds;
185 else if (!strncmp(p, "ssh://", 6) || !strncmp(p, "ssh6://", 7) ||
186 !strncmp(p, "ssh4://", 7)) {
187 #ifndef WITH_TCP
188 return GPG_ERR_NOT_IMPLEMENTED;
189 #else
190 char *host = NULL;
191 int port = -1;
192 char *identity = NULL;
193 char *known_hosts = NULL;
194 char *username = NULL;
196 if (!strncmp(p, "ssh6://", 7)) {
197 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV6);
198 p += 7;
200 else if (!strncmp(p, "ssh4://", 7)) {
201 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV4);
202 p += 7;
204 else {
205 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IP_ANY);
206 p += 6;
209 if (rc)
210 return rc;
212 rc = _parse_ssh_url(p, &host, &port, &username, &identity,
213 &known_hosts);
215 if (rc)
216 goto fail;
218 if (async)
219 rc = pwmd_ssh_connect_async(pwm, host, port, identity, username,
220 known_hosts);
221 else
222 rc = pwmd_ssh_connect(pwm, host, port, identity, username,
223 known_hosts);
225 fail:
226 if (host)
227 pwmd_free(host);
229 if (username)
230 pwmd_free(username);
232 if (identity)
233 pwmd_free(identity);
235 if (known_hosts)
236 pwmd_free(known_hosts);
238 return rc;
239 #endif
242 connect_uds:
243 rc = pwmd_connect(pwm, p);
244 pwm->state = ASYNC_DONE;
245 return rc;
248 gpg_error_t pwmd_connect_url(pwm_t *pwm, const char *url)
250 return _pwmd_connect_url(pwm, url, 0);
253 gpg_error_t pwmd_connect_url_async(pwm_t *pwm, const char *url)
255 return _pwmd_connect_url(pwm, url, 1);
258 gpg_error_t pwmd_connect(pwm_t *pwm, const char *path)
260 char *socketpath = NULL;
261 assuan_context_t ctx;
262 struct passwd pw;
263 char *pwbuf;
264 gpg_error_t rc;
266 if (!pwm)
267 return GPG_ERR_INV_ARG;
269 pwbuf = _getpwuid(&pw);
271 if (!pwbuf)
272 return gpg_error_from_errno(errno);
274 if (!path || !*path)
275 socketpath = pwmd_strdup_printf("%s/.pwmd/socket", pw.pw_dir);
276 else
277 socketpath = _expand_homedir((char *)path, &pw);
279 pwmd_free(pwbuf);
281 if (!socketpath)
282 return gpg_error_from_errno(ENOMEM);
284 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
285 pwmd_free(socketpath);
287 if (rc)
288 return gpg_err_code(rc);
290 pwm->ctx = ctx;
291 return _connect_finalize(pwm);
294 static void disconnect(pwm_t *pwm)
296 if (!pwm || !pwm->ctx)
297 return;
299 assuan_disconnect(pwm->ctx);
300 pwm->ctx = NULL;
301 pwm->fd = -1;
304 void pwmd_close(pwm_t *pwm)
306 if (!pwm)
307 return;
309 disconnect(pwm);
311 if (pwm->password)
312 pwmd_free(pwm->password);
314 if (pwm->title)
315 pwmd_free(pwm->title);
317 if (pwm->desc)
318 pwmd_free(pwm->desc);
320 if (pwm->prompt)
321 pwmd_free(pwm->prompt);
323 if (pwm->pinentry_tty)
324 pwmd_free(pwm->pinentry_tty);
326 if (pwm->pinentry_display)
327 pwmd_free(pwm->pinentry_display);
329 if (pwm->pinentry_term)
330 pwmd_free(pwm->pinentry_term);
332 if (pwm->lcctype)
333 pwmd_free(pwm->lcctype);
335 if (pwm->lcmessages)
336 pwmd_free(pwm->lcmessages);
338 if (pwm->filename)
339 pwmd_free(pwm->filename);
341 if (pwm->name)
342 pwmd_free(pwm->name);
344 #ifdef WITH_TCP
345 if (pwm->tcp_conn)
346 _free_ssh_conn(pwm->tcp_conn);
347 #endif
349 #ifdef WITH_PINENTRY
350 if (pwm->pctx)
351 _pinentry_disconnect(pwm);
352 #endif
354 pwmd_free(pwm);
357 static gpg_error_t do_async_command(pwm_t *pwm, char **result)
359 pwmd_async_t s;
360 gpg_error_t rc;
362 do {
363 s = pwmd_process(pwm, &rc, result);
365 if (s != ASYNC_DONE) {
366 #ifdef WITH_LIBPTH
367 pth_usleep(50000);
368 #else
369 usleep(50000);
370 #endif
372 } while (s != ASYNC_DONE);
374 return rc;
377 gpg_error_t pwmd_ssh_connect_async(pwm_t *pwm, const char *host, int port,
378 const char *identity, const char *user, const char *known_hosts)
380 #ifndef WITH_TCP
381 return GPG_ERR_NOT_IMPLEMENTED;
382 #else
383 return _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
384 known_hosts, ASYNC_CMD_CONNECT);
385 #endif
388 gpg_error_t pwmd_ssh_connect(pwm_t *pwm, const char *host, int port,
389 const char *identity, const char *user, const char *known_hosts)
391 #ifndef WITH_TCP
392 return GPG_ERR_NOT_IMPLEMENTED;
393 #else
394 gpg_error_t rc;
396 rc = _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
397 known_hosts, ASYNC_CMD_CONNECT);
398 return rc || do_async_command(pwm, NULL);
399 #endif
402 gpg_error_t pwmd_get_hostkey(pwm_t *pwm, const char *host, int port,
403 char **result)
405 #ifndef WITH_TCP
406 return GPG_ERR_NOT_IMPLEMENTED;
407 #else
408 gpg_error_t rc;
410 rc = _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
411 ASYNC_CMD_HOSTKEY);
413 return rc || do_async_command(pwm, result);
414 #endif
417 gpg_error_t pwmd_get_hostkey_async(pwm_t *pwm, const char *host, int port)
419 #ifndef WITH_TCP
420 return GPG_ERR_NOT_IMPLEMENTED;
421 #else
422 return _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
423 ASYNC_CMD_HOSTKEY);
424 #endif
427 static int inquire_realloc_cb(void *data, const void *buffer, size_t len)
429 membuf_t *mem = (membuf_t *)data;
430 void *p;
432 if (!buffer)
433 return 0;
435 if ((p = pwmd_realloc(mem->buf, mem->len + len)) == NULL)
436 return gpg_error_from_errno(ENOMEM);
438 mem->buf = p;
439 memcpy((char *)mem->buf + mem->len, buffer, len);
440 mem->len += len;
441 return 0;
444 static int inquire_cb(void *data, const char *keyword)
446 pwm_t *pwm = (pwm_t *)data;
447 gpg_error_t rc = 0;
448 int is_eagain = 0;
450 /* Shouldn't get this far without a callback. */
451 if (!pwm->inquire_func)
452 return GPG_ERR_INV_ARG;
454 for (;;) {
455 char *result = NULL;
456 size_t len;
457 gpg_error_t arc;
459 rc = pwm->inquire_func(pwm->inquire_data, keyword, rc, &result, &len);
460 rc = gpg_err_code(rc);
462 if (rc == GPG_ERR_EOF || !rc) {
463 if (len <= 0 && !result) {
464 rc = 0;
465 break;
467 else if ((len <= 0 && result) || (len && !result)) {
468 rc = GPG_ERR_INV_ARG;
469 break;
472 eagain:
473 is_eagain = 0;
474 arc = assuan_send_data(pwm->ctx, result, len);
475 arc = gpg_err_code(arc);
477 if (rc == GPG_ERR_EOF) {
478 rc = arc;
479 break;
482 rc = arc;
484 if (rc == GPG_ERR_EAGAIN) {
485 rc = 0;
486 is_eagain = 1;
487 goto process;
490 else if (rc)
491 break;
493 if (!rc) {
494 pwm->inquire_sent += len;
496 if (pwm->status_func) {
497 char buf[ASSUAN_LINELENGTH];
499 snprintf(buf, sizeof(buf), "XFER %u %u", pwm->inquire_sent,
500 pwm->inquire_total);
501 rc = pwm->status_func(pwm->status_data, buf);
503 if (rc)
504 continue;
507 process:
508 rc = _pwmd_process(pwm);
510 if (rc == GPG_ERR_EAGAIN)
511 rc = 0;
514 if (!rc && is_eagain)
515 goto eagain;
518 return gpg_err_code(rc);
521 static gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, ...)
523 char *buf;
524 gpg_error_t rc;
525 va_list ap;
526 int len;
528 if (pwm->state == ASYNC_DONE)
529 pwm->state = ASYNC_INIT;
531 if (pwm->state != ASYNC_INIT)
532 return GPG_ERR_INV_STATE;
534 buf = pwmd_malloc(ASSUAN_LINELENGTH+1);
536 if (!buf)
537 return gpg_error_from_errno(ENOMEM);
539 va_start(ap, cmd);
540 len = vsnprintf(buf, ASSUAN_LINELENGTH+1, cmd, ap);
541 va_end(ap);
543 if (len >= ASSUAN_LINELENGTH+1) {
544 pwmd_free(buf);
545 return GPG_ERR_LINE_TOO_LONG;
548 rc = assuan_write_line(pwm->ctx, buf);
549 pwmd_free(buf);
551 if (!rc)
552 pwm->state = ASYNC_PROCESS;
554 return gpg_err_code(rc);
557 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
559 char *p = NULL;
560 const char *f = NULL;
561 gpg_error_t rc;
563 if (!pwm || !filename)
564 return GPG_ERR_INV_ARG;
566 if (!pwm->ctx)
567 return GPG_ERR_INV_STATE;
569 if (pwm->cmd != ASYNC_CMD_NONE)
570 return GPG_ERR_ASS_NESTED_COMMANDS;
572 if (pwm->lastcmd == ASYNC_CMD_NONE) {
573 pwm->pin_try = 0;
575 if (pwm->filename)
576 pwmd_free(pwm->filename);
578 pwm->filename = pwmd_strdup(filename);
580 if (!pwm->filename)
581 return gpg_error_from_errno(ENOMEM);
583 gpg_error_t rc = send_pinentry_options(pwm);
585 if (rc)
586 return rc;
588 rc = get_custom_passphrase(pwm, &p);
590 if (rc && rc != GPG_ERR_NO_DATA)
591 return rc;
593 f = filename;
595 #ifdef WITH_PINENTRY
596 else if (pwm->lastcmd == ASYNC_CMD_OPEN2) {
597 p = pwm->_password;
598 f = pwm->filename;
600 #endif
601 else if (pwm->lastcmd == ASYNC_CMD_OPEN) {
602 rc = set_pinentry_retry(pwm);
604 if (rc)
605 return rc;
607 p = pwm->password;
608 f = filename;
610 else
611 return GPG_ERR_INV_STATE;
613 pwm->cmd = ASYNC_CMD_OPEN;
614 return do_nb_command(pwm, "OPEN %s %s", f, p ? p : "");
617 gpg_error_t pwmd_save_async(pwm_t *pwm)
619 char *p = NULL;
621 if (!pwm)
622 return GPG_ERR_INV_ARG;
624 if (!pwm->ctx)
625 return GPG_ERR_INV_STATE;
627 if (pwm->cmd != ASYNC_CMD_NONE)
628 return GPG_ERR_ASS_NESTED_COMMANDS;
630 if (pwm->lastcmd != ASYNC_CMD_SAVE2) {
631 gpg_error_t rc = send_pinentry_options(pwm);
633 if (rc)
634 return rc;
636 rc = get_custom_passphrase(pwm, &p);
638 if (rc && rc != GPG_ERR_NO_DATA)
639 return rc;
641 #ifdef WITH_PINENTRY
642 else
643 p = pwm->_password;
644 #endif
646 pwm->cmd = ASYNC_CMD_SAVE;
647 return do_nb_command(pwm, "SAVE %s", p ? p : "");
650 static gpg_error_t parse_assuan_line(pwm_t *pwm)
652 gpg_error_t rc;
653 char *line;
654 size_t len;
656 rc = assuan_read_line(pwm->ctx, &line, &len);
658 if (!rc) {
659 if (line[0] == 'O' && line[1] == 'K' &&
660 (line[2] == 0 || line[2] == ' ')) {
661 pwm->state = ASYNC_DONE;
663 else if (line[0] == '#') {
665 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
666 if (pwm->status_func) {
667 rc = pwm->status_func(pwm->status_data,
668 line[1] == 0 ? line+1 : line+2);
671 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
672 (line[3] == 0 || line[3] == ' ')) {
673 line += 4;
674 rc = atoi(line);
675 pwm->state = ASYNC_DONE;
679 return gpg_err_code(rc);
682 gpg_error_t pwmd_pending_line(pwm_t *pwm)
684 if (!pwm)
685 return GPG_ERR_INV_ARG;
687 if (!pwm->ctx)
688 return GPG_ERR_INV_STATE;
690 return assuan_pending_line(pwm->ctx) ? 0 : GPG_ERR_NO_DATA;
693 static pwmd_async_t reset_async(pwm_t *pwm, int done)
695 pwm->state = ASYNC_INIT;
696 pwm->cmd = pwm->lastcmd = ASYNC_CMD_NONE;
698 #ifdef WITH_PINENTRY
699 if (pwm->nb_fd != -1) {
700 close(pwm->nb_fd);
701 pwm->nb_fd = -1;
704 if (pwm->_password) {
705 pwmd_free(pwm->_password);
706 pwm->_password = NULL;
708 #endif
709 #ifdef WITH_TCP
710 if (pwm->tcp_conn)
711 pwm->tcp_conn->rc = 0;
713 if (done && pwm->tcp_conn) {
714 _free_ssh_conn(pwm->tcp_conn);
715 pwm->tcp_conn = NULL;
717 #endif
719 return ASYNC_DONE;
723 * Used for processing status messages when not in an async command and for
724 * waiting for the result from pwmd_open_async() and pwmd_save_async().
726 static gpg_error_t _pwmd_process(pwm_t *pwm)
728 gpg_error_t rc = 0;
729 fd_set fds;
730 struct timeval tv = {0, 0};
731 int n;
733 FD_ZERO(&fds);
734 FD_SET(pwm->fd, &fds);
735 #ifdef WITH_LIBPTH
736 n = pth_select(pwm->fd+1, &fds, NULL, NULL, &tv);
737 #else
738 n = select(pwm->fd+1, &fds, NULL, NULL, &tv);
739 #endif
741 if (n == -1)
742 return gpg_error_from_syserror();
744 if (n > 0) {
745 if (FD_ISSET(pwm->fd, &fds))
746 rc = parse_assuan_line(pwm);
749 while (!rc && assuan_pending_line(pwm->ctx))
750 rc = parse_assuan_line(pwm);
752 return gpg_err_code(rc);
755 static void reset_handle(pwm_t *h)
757 h->fd = -1;
758 #ifdef WITH_PINENTRY
759 if (h->pctx)
760 _pinentry_disconnect(h);
762 h->nb_fd = -1;
763 #endif
764 h->pin_try = 0;
765 reset_async(h, 0);
768 gpg_error_t pwmd_disconnect(pwm_t *pwm)
770 if (!pwm)
771 return GPG_ERR_INV_ARG;
773 #ifdef WITH_TCP
774 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
775 #else
776 if (pwm->fd == -1)
777 #endif
778 return GPG_ERR_INV_STATE;
780 if (pwm->fd != 1)
781 disconnect(pwm);
782 #ifdef WITH_TCP
783 else
784 _ssh_disconnect(pwm);
785 #endif
787 reset_handle(pwm);
788 return 0;
791 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc, char **result)
793 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
794 fd_set fds;
795 int n;
796 struct timeval tv = {0, 0};
797 #endif
799 if (result)
800 *result = NULL;
802 if (!rc)
803 return GPG_ERR_INV_ARG;
805 *rc = 0;
807 if (!pwm) {
808 *rc = GPG_ERR_INV_ARG;
809 return ASYNC_DONE;
811 else if (!pwm->ctx) {
812 switch (pwm->cmd) {
813 default:
814 *rc = GPG_ERR_INV_STATE;
815 return ASYNC_DONE;
816 #ifdef WITH_TCP
817 case ASYNC_CMD_DNS:
818 case ASYNC_CMD_CONNECT:
819 case ASYNC_CMD_HOSTKEY:
820 break;
821 #endif
825 /* When not in a command, this will let libassuan process status messages
826 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
827 * descriptor returned by pwmd_get_fd() to determine when this should be
828 * called or call pwmd_pending_line() to determine whether a buffered line
829 * needs to be processed. */
830 if (pwm->cmd == ASYNC_CMD_NONE) {
831 *rc = _pwmd_process(pwm);
832 return ASYNC_DONE;
835 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
836 if (pwm->state == ASYNC_DONE) {
837 *rc = _pwmd_process(pwm);
838 return reset_async(pwm, 0);
841 if (pwm->state != ASYNC_PROCESS) {
842 *rc = GPG_ERR_INV_STATE;
843 return ASYNC_DONE;
846 #ifdef WITH_TCP
847 if (pwm->cmd == ASYNC_CMD_DNS) {
848 fd_set rfds, wfds;
850 if (pwm->tcp_conn->rc) {
851 *rc = pwm->tcp_conn->rc;
852 return reset_async(pwm, 1);
855 FD_ZERO(&rfds);
856 FD_ZERO(&wfds);
857 n = ares_fds(pwm->tcp_conn->chan, &rfds, &wfds);
859 /* Shouldn't happen. */
860 if (!n)
861 return pwm->state;
863 #ifdef WITH_LIBPTH
864 n = pth_select(n, &rfds, &wfds, NULL, &tv);
865 #else
866 n = select(n, &rfds, &wfds, NULL, &tv);
867 #endif
869 if (n < 0) {
870 *rc = gpg_error_from_syserror();
871 return reset_async(pwm, 1);
874 if (n > 0)
875 ares_process(pwm->tcp_conn->chan, &rfds, &wfds);
877 return pwm->state;
879 else if (pwm->cmd == ASYNC_CMD_CONNECT) {
880 if (pwm->tcp_conn->rc == GPG_ERR_EINPROGRESS) {
881 int ret;
882 socklen_t len = sizeof(int);
884 FD_ZERO(&fds);
885 FD_SET(pwm->tcp_conn->fd, &fds);
886 #ifdef WITH_LIBPTH
887 n = pth_select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
888 #else
889 n = select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
890 #endif
892 if (!n || !FD_ISSET(pwm->tcp_conn->fd, &fds))
893 return pwm->state;
894 else if (n == -1) {
895 *rc = gpg_error_from_syserror();
896 return reset_async(pwm, 1);
899 ret = getsockopt(pwm->tcp_conn->fd, SOL_SOCKET, SO_ERROR, &n, &len);
901 if (ret || n) {
902 *rc = ret ? gpg_error_from_syserror() : gpg_error_from_errno(n);
903 return reset_async(pwm, 1);
906 pwm->tcp_conn->state = SSH_NONE;
907 pwm->tcp_conn->rc = 0;
908 *rc = _setup_ssh_session(pwm);
910 if (*rc && *rc != GPG_ERR_EAGAIN)
911 return reset_async(pwm, 1);
913 else if (pwm->tcp_conn->rc) {
914 *rc = pwm->tcp_conn->rc;
915 return reset_async(pwm, 1);
918 switch (pwm->tcp_conn->state) {
919 case SSH_INIT:
920 *rc = _setup_ssh_init(pwm);
921 break;
922 case SSH_AUTHLIST:
923 *rc = _setup_ssh_authlist(pwm);
924 break;
925 case SSH_AUTH:
926 *rc = _setup_ssh_auth(pwm);
927 break;
928 case SSH_CHANNEL:
929 *rc = _setup_ssh_channel(pwm);
930 break;
931 case SSH_SHELL:
932 *rc = _setup_ssh_shell(pwm);
933 break;
934 default:
935 break;
938 if (*rc == GPG_ERR_EAGAIN) {
939 *rc = 0;
940 return ASYNC_PROCESS;
943 if (!*rc) {
944 switch (pwm->tcp_conn->cmd) {
945 case ASYNC_CMD_HOSTKEY:
946 *result = pwmd_strdup(pwm->tcp_conn->hostkey);
948 if (!*result)
949 *rc = GPG_ERR_ENOMEM;
950 break;
951 default:
952 break;
956 return reset_async(pwm, *rc ? 1 : 0);
958 #endif
960 #ifdef WITH_PINENTRY
961 if (pwm->cmd == ASYNC_CMD_OPEN2 || pwm->cmd == ASYNC_CMD_SAVE2) {
962 int status;
964 if (pwm->nb_fd == -1) {
965 *rc = GPG_ERR_INV_STATE;
966 return reset_async(pwm, 0);
969 FD_ZERO(&fds);
970 FD_SET(pwm->nb_fd, &fds);
971 FD_SET(pwm->fd, &fds);
972 #ifdef WITH_LIBPTH
973 n = pth_select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
974 #else
975 n = select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
976 #endif
977 if (n < 0) {
978 *rc = gpg_error_from_syserror();
979 return reset_async(pwm, 0);
982 if (n > 0 && FD_ISSET(pwm->nb_fd, &fds)) {
983 pwmd_nb_status_t nb;
984 #ifdef WITH_LIBPTH
985 size_t len = pth_read(pwm->nb_fd, &nb, sizeof(nb));
986 #else
987 size_t len = read(pwm->nb_fd, &nb, sizeof(nb));
988 #endif
989 waitpid(pwm->nb_pid, &status, WNOHANG);
991 if (len != sizeof(nb)) {
992 memset(&nb, 0, sizeof(pwmd_nb_status_t));
993 *rc = gpg_error_from_syserror();
994 return reset_async(pwm, 0);
997 *rc = nb.error;
999 if (*rc)
1000 return reset_async(pwm, 0);
1002 /* Since the non-blocking pinentry returned a success, do a
1003 * non-blocking OPEN or SAVE. */
1004 pwmd_async_cmd_t c = pwm->cmd;
1005 reset_async(pwm, 0);
1006 pwm->_password = pwmd_strdup(nb.password);
1007 memset(&nb, 0, sizeof(pwmd_nb_status_t));
1008 pwm->lastcmd = c;
1010 if (!pwm->_password) {
1011 *rc = gpg_error_from_errno(ENOMEM);
1012 return reset_async(pwm, 0);
1015 if (c == ASYNC_CMD_SAVE2)
1016 *rc = pwmd_save_async(pwm);
1017 else
1018 *rc = pwmd_open_async(pwm, pwm->filename);
1020 if (*rc) {
1021 reset_async(pwm, 0);
1022 return ASYNC_DONE;
1025 return ASYNC_PROCESS;
1028 /* Fall through so status messages can be processed during the
1029 * pinentry. */
1031 #endif
1033 if (pwm->fd < 0) {
1034 *rc = GPG_ERR_INV_STATE;
1035 return reset_async(pwm, 0);
1038 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
1039 * retries. */
1040 *rc = _pwmd_process(pwm);
1042 if (*rc && *rc != GPG_ERR_INV_PASSPHRASE)
1043 return reset_async(pwm, 0);
1045 if (pwm->cmd == ASYNC_CMD_OPEN &&
1046 *rc == GPG_ERR_INV_PASSPHRASE &&
1047 #ifdef WITH_TCP
1048 (!pwm->tcp_conn || (pwm->tcp_conn && pwm->lastcmd == ASYNC_CMD_OPEN2)) &&
1049 #endif
1050 ++pwm->pin_try < pwm->pinentry_tries) {
1051 if (!get_custom_passphrase(pwm, NULL))
1052 goto done;
1054 #ifdef WITH_PINENTRY
1055 if (pwm->_password) {
1056 reset_async(pwm, 0);
1057 pwm->lastcmd = ASYNC_CMD_OPEN2;
1058 *rc = pwmd_open_async2(pwm, pwm->filename);
1060 else {
1061 #endif
1062 reset_async(pwm, 0);
1063 pwm->lastcmd = ASYNC_CMD_OPEN;
1064 *rc = pwmd_open_async(pwm, pwm->filename);
1065 #ifdef WITH_PINENTRY
1067 #endif
1070 done:
1071 if (*rc || pwm->state == ASYNC_DONE)
1072 return reset_async(pwm, 0);
1074 return pwm->state;
1077 gpg_error_t _assuan_command(pwm_t *pwm, assuan_context_t ctx,
1078 char **result, const char *cmd)
1080 membuf_t data;
1081 gpg_error_t rc;
1083 if (!cmd || !*cmd)
1084 return GPG_ERR_INV_ARG;
1086 if (strlen(cmd) >= ASSUAN_LINELENGTH+1)
1087 return GPG_ERR_LINE_TOO_LONG;
1089 data.len = 0;
1090 data.buf = NULL;
1091 rc = assuan_transact(ctx, cmd, inquire_realloc_cb, &data,
1092 #ifdef WITH_QUALITY
1093 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1094 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1095 #else
1096 inquire_cb, pwm,
1097 #endif
1098 pwm->status_func, pwm->status_data);
1100 if (rc) {
1101 if (data.buf) {
1102 pwmd_free(data.buf);
1103 data.buf = NULL;
1106 else {
1107 if (data.buf) {
1108 inquire_realloc_cb(&data, "", 1);
1110 if (!result) {
1111 pwmd_free(data.buf);
1112 rc = GPG_ERR_INV_ARG;
1114 else
1115 *result = (char *)data.buf;
1119 return gpg_err_code(rc);
1122 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_cb_t fn,
1123 void *data)
1125 if (!pwm || !cmd || !fn)
1126 return GPG_ERR_INV_ARG;
1128 if (!pwm->ctx)
1129 return GPG_ERR_INV_STATE;
1131 pwm->inquire_func = fn;
1132 pwm->inquire_data = data;
1133 pwm->inquire_sent = 0;
1134 return _assuan_command(pwm, pwm->ctx, NULL, cmd);
1137 gpg_error_t pwmd_command_ap(pwm_t *pwm, char **result, const char *cmd,
1138 va_list ap)
1140 char *buf;
1141 size_t len;
1142 va_list ap2;
1144 if (!pwm || !cmd)
1145 return GPG_ERR_INV_ARG;
1147 if (!pwm->ctx)
1148 return GPG_ERR_INV_STATE;
1151 * C99 allows the dst pointer to be null which will calculate the length
1152 * of the would-be result and return it.
1154 va_copy(ap2, ap);
1155 len = vsnprintf(NULL, 0, cmd, ap)+1;
1156 buf = (char *)pwmd_malloc(len);
1158 if (!buf) {
1159 va_end(ap2);
1160 return gpg_error_from_errno(ENOMEM);
1163 len = vsnprintf(buf, len, cmd, ap2);
1164 va_end(ap2);
1166 if (buf[strlen(buf)-1] == '\n')
1167 buf[strlen(buf)-1] = 0;
1169 if (buf[strlen(buf)-1] == '\r')
1170 buf[strlen(buf)-1] = 0;
1172 gpg_error_t rc = _assuan_command(pwm, pwm->ctx, result, buf);
1173 pwmd_free(buf);
1174 return rc;
1177 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
1179 va_list ap;
1181 if (!pwm || !cmd)
1182 return GPG_ERR_INV_ARG;
1184 if (!pwm->ctx)
1185 return GPG_ERR_INV_STATE;
1187 if (result)
1188 *result = NULL;
1190 va_start(ap, cmd);
1191 gpg_error_t rc = pwmd_command_ap(pwm, result, cmd, ap);
1192 va_end(ap);
1193 return rc;
1196 static gpg_error_t send_pinentry_options(pwm_t *pwm)
1198 gpg_error_t rc;
1200 if (pwm->pinentry_path) {
1201 rc = pwmd_command(pwm, NULL, "SET PINENTRY_PATH=%s",
1202 pwm->pinentry_path);
1204 if (rc)
1205 return rc;
1208 if (pwm->pinentry_tty) {
1209 rc = pwmd_command(pwm, NULL, "SET TTYNAME=%s", pwm->pinentry_tty);
1211 if (rc)
1212 return rc;
1215 if (pwm->pinentry_term) {
1216 rc = pwmd_command(pwm, NULL, "SET TTYTYPE=%s", pwm->pinentry_term);
1218 if (rc)
1219 return rc;
1222 if (pwm->pinentry_display) {
1223 rc = pwmd_command(pwm, NULL, "SET DISPLAY=%s",
1224 pwm->pinentry_display);
1226 if (rc)
1227 return rc;
1230 if (pwm->title) {
1231 rc = pwmd_command(pwm, NULL, "SET TITLE=%s", pwm->title);
1233 if (rc)
1234 return rc;
1237 if (pwm->desc) {
1238 rc = pwmd_command(pwm, NULL, "SET DESC=%s", pwm->desc);
1240 if (rc)
1241 return rc;
1244 if (pwm->prompt) {
1245 rc = pwmd_command(pwm, NULL, "SET PROMPT=%s", pwm->prompt);
1247 if (rc)
1248 return rc;
1251 if (pwm->lcctype) {
1252 rc = pwmd_command(pwm, NULL, "SET LC_CTYPE=%s", pwm->lcctype);
1254 if (rc)
1255 return rc;
1258 if (pwm->lcmessages) {
1259 rc = pwmd_command(pwm, NULL, "SET LC_MESSAGES=%s", pwm->lcmessages);
1261 if (rc)
1262 return rc;
1265 if (pwm->pinentry_timeout >= 0 && !pwm->pin_try) {
1266 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=%i",
1267 pwm->pinentry_timeout);
1269 if (rc)
1270 return rc;
1273 return 0;
1276 gpg_error_t pwmd_socket_type(pwm_t *pwm, pwmd_socket_t *result)
1278 if (!pwm || !result)
1279 return GPG_ERR_INV_ARG;
1281 #ifdef WITH_TCP
1282 if ((pwm->fd == -1 && !pwm->tcp_conn) ||
1283 (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1))
1284 #else
1285 if (pwm->fd == -1)
1286 #endif
1287 return GPG_ERR_INV_STATE;
1289 #ifdef WITH_TCP
1290 *result = pwm->tcp_conn ? PWMD_SOCKET_SSH : PWMD_SOCKET_LOCAL;
1291 #else
1292 *result = PWMD_SOCKET_LOCAL;
1293 #endif
1294 return 0;
1297 static gpg_error_t set_pinentry_retry(pwm_t *pwm)
1299 gpg_error_t rc = 0;
1301 if (pwm->pin_try == 1) {
1302 rc = pwmd_command(pwm, NULL, "SET TITLE=%s",
1303 N_("Invalid passphrase, please try again."));
1305 if (rc)
1306 return rc;
1308 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=0");
1311 return rc;
1314 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result)
1316 gpg_error_t rc = GPG_ERR_NO_DATA;
1318 if (result)
1319 *result = NULL;
1320 else {
1321 if (pwm->password || pwm->passfunc)
1322 return 0;
1325 if (pwm->password) {
1326 rc = 0;
1327 *result = pwm->password;
1329 else if (pwm->passfunc)
1330 rc = pwm->passfunc(pwm->passdata, result);
1332 return rc;
1335 static gpg_error_t do_pwmd_open(pwm_t *pwm, const char *filename, int nb,
1336 int local_pinentry)
1338 char *result = NULL;
1339 char *password = NULL;
1340 gpg_error_t rc;
1342 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1343 pwm->pin_try = 0;
1345 if (!pwm || !filename || !*filename)
1346 return GPG_ERR_INV_ARG;
1348 if (!pwm->ctx)
1349 return GPG_ERR_INV_STATE;
1352 * Avoid calling pinentry if the password is cached on the server or if
1353 * this is a new file.
1355 rc = pwmd_command(pwm, &result, "ISCACHED %s", filename);
1357 if (rc == GPG_ERR_ENOENT)
1358 goto gotpassword;
1360 if (rc && rc != GPG_ERR_NOT_FOUND)
1361 return rc;
1363 if (rc == GPG_ERR_NOT_FOUND) {
1364 rc = get_custom_passphrase(pwm, &password);
1366 if (rc && rc != GPG_ERR_NO_DATA)
1367 return rc;
1368 else if (rc == GPG_ERR_NO_DATA)
1369 rc = GPG_ERR_NOT_FOUND;
1370 else
1371 goto gotpassword;
1374 #ifdef WITH_PINENTRY
1375 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1376 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1377 if (!pwm->pin_try) {
1378 rc = pwmd_command(pwm, NULL, "SET ENABLE_PINENTRY=0");
1380 if (rc)
1381 return rc;
1384 rc = _pinentry_open(pwm, filename, &password, nb);
1386 /* pwmd_process() should be called if using a non-blocking local
1387 * pinentry. */
1388 if (rc || (!rc && nb))
1389 return rc;
1391 #endif
1393 gotpassword:
1394 reset_async(pwm, 0);
1396 #ifdef WITH_TCP
1397 if (!local_pinentry && !pwm->tcp_conn && !pwm->pin_try) {
1398 #else
1399 if (!local_pinentry && !pwm->pin_try) {
1400 #endif
1401 rc = send_pinentry_options(pwm);
1403 if (rc)
1404 return rc;
1407 rc = pwmd_command(pwm, NULL, "OPEN %s %s", filename,
1408 password ? password : "");
1411 * Keep the user defined password set with pwmd_setopt(). The password may
1412 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1414 if (!pwm->passfunc && password && password != pwm->password)
1415 pwmd_free(password);
1417 if (rc == GPG_ERR_INV_PASSPHRASE) {
1418 if (++pwm->pin_try < pwm->pinentry_tries) {
1419 if (!get_custom_passphrase(pwm, NULL))
1420 goto done;
1422 #ifdef WITH_PINENTRY
1423 #ifdef WITH_TCP
1424 if (pwm->tcp_conn && !local_pinentry)
1425 return rc;
1426 else if (local_pinentry)
1427 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1428 else
1429 #else
1430 if (local_pinentry)
1431 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1432 else
1433 #endif
1434 #else
1435 #ifdef WITH_TCP
1436 if (pwm->tcp_conn)
1437 return rc;
1438 else
1439 #endif
1440 #endif
1441 rc = set_pinentry_retry(pwm);
1443 if (rc)
1444 return rc;
1446 goto gotpassword;
1448 #ifdef WITH_PINENTRY
1449 else if (local_pinentry)
1450 _pinentry_disconnect(pwm);
1451 #endif
1453 done:
1454 return rc;
1456 #ifdef WITH_PINENTRY
1457 else if (rc && local_pinentry)
1458 _pinentry_disconnect(pwm);
1459 #endif
1461 if (!rc) {
1462 if (pwm->filename)
1463 pwmd_free(pwm->filename);
1465 pwm->filename = pwmd_strdup(filename);
1468 return rc;
1471 gpg_error_t pwmd_open2(pwm_t *pwm, const char *filename)
1473 #ifndef WITH_PINENTRY
1474 return GPG_ERR_NOT_IMPLEMENTED;
1475 #else
1476 return do_pwmd_open(pwm, filename, 0, 1);
1477 #endif
1480 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
1482 return do_pwmd_open(pwm, filename, 0, 0);
1485 gpg_error_t pwmd_open_async2(pwm_t *pwm, const char *filename)
1487 #ifndef WITH_PINENTRY
1488 return GPG_ERR_NOT_IMPLEMENTED;
1489 #else
1490 if (!pwm || !filename)
1491 return GPG_ERR_INV_ARG;
1493 if (!pwm->ctx)
1494 return GPG_ERR_INV_STATE;
1496 if (pwm->cmd != ASYNC_CMD_NONE)
1497 return GPG_ERR_ASS_NESTED_COMMANDS;
1499 /* Initialize a new command since this is not a pinentry retry. */
1500 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1501 pwm->pin_try = 0;
1503 pwm->cmd = ASYNC_CMD_OPEN2;
1504 pwm->state = ASYNC_PROCESS;
1505 gpg_error_t rc = do_pwmd_open(pwm, filename, 1, 1);
1507 if (rc)
1508 reset_async(pwm, 0);
1510 return rc;
1511 #endif
1514 static gpg_error_t do_pwmd_save(pwm_t *pwm, int nb, int local_pinentry)
1516 char *result = NULL;
1517 char *password = NULL;
1518 gpg_error_t rc;
1520 if (!pwm)
1521 return GPG_ERR_INV_ARG;
1523 if (!pwm->ctx)
1524 return GPG_ERR_INV_STATE;
1526 rc = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1528 if (rc == GPG_ERR_ENOENT)
1529 rc = GPG_ERR_NOT_FOUND;
1531 if (rc && rc != GPG_ERR_NOT_FOUND)
1532 return rc;
1534 if (rc == GPG_ERR_NOT_FOUND) {
1535 rc = get_custom_passphrase(pwm, &password);
1537 if (rc && rc != GPG_ERR_NO_DATA)
1538 return rc;
1539 else if (rc == GPG_ERR_NO_DATA)
1540 rc = GPG_ERR_NOT_FOUND;
1541 else
1542 goto gotpassword;
1545 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1546 #ifdef WITH_PINENTRY
1547 /* Get the password using the LOCAL pinentry. */
1548 if (nb) {
1549 int p[2];
1550 pid_t pid;
1551 pwmd_nb_status_t pw;
1553 if (pipe(p) == -1)
1554 return gpg_error_from_syserror();
1556 #ifdef WITH_LIBPTH
1557 pid = pth_fork();
1558 #else
1559 pid = fork();
1560 #endif
1562 switch (pid) {
1563 case 0:
1564 close(p[0]);
1565 pw.fd = p[0];
1566 password = NULL;
1567 pw.error = _do_save_getpin(pwm, &password);
1569 if (!pw.error) {
1570 snprintf(pw.password, sizeof(pw.password), "%s",
1571 password);
1572 pwmd_free(password);
1574 #ifdef WITH_LIBPTH
1575 pth_write(p[1], &pw, sizeof(pw));
1576 #else
1577 write(p[1], &pw, sizeof(pw));
1578 #endif
1579 memset(&pw, 0, sizeof(pw));
1580 close(p[1]);
1581 _exit(0);
1582 break;
1583 case -1:
1584 rc = gpg_error_from_syserror();
1585 close(p[0]);
1586 close(p[1]);
1587 return rc;
1588 default:
1589 break;
1592 close(p[1]);
1593 pwm->nb_fd = p[0];
1594 pwm->nb_pid = pid;
1595 return 0;
1598 rc = _do_save_getpin(pwm, &password);
1600 if (rc)
1601 return rc;
1602 #endif
1604 else
1605 pwm->state = ASYNC_DONE;
1607 gotpassword:
1608 reset_async(pwm, 0);
1610 #ifdef WITH_TCP
1611 if (!local_pinentry && !pwm->tcp_conn) {
1612 #else
1613 if (!local_pinentry) {
1614 #endif
1615 rc = send_pinentry_options(pwm);
1617 if (rc)
1618 return rc;
1621 rc = pwmd_command(pwm, NULL, "SAVE %s", password ? password : "");
1623 if (!pwm->passfunc && password && password != pwm->password)
1624 pwmd_free(password);
1626 return rc;
1629 gpg_error_t pwmd_save_async2(pwm_t *pwm)
1631 #ifndef WITH_PINENTRY
1632 return GPG_ERR_NOT_IMPLEMENTED;
1633 #else
1634 if (!pwm)
1635 return GPG_ERR_INV_ARG;
1637 if (!pwm->ctx)
1638 return GPG_ERR_INV_STATE;
1640 if (pwm->cmd != ASYNC_CMD_NONE)
1641 return GPG_ERR_ASS_NESTED_COMMANDS;
1643 pwm->cmd = ASYNC_CMD_SAVE2;
1644 pwm->state = ASYNC_PROCESS;
1645 gpg_error_t rc = do_pwmd_save(pwm, 1, 1);
1647 if (rc)
1648 reset_async(pwm, 0);
1650 return rc;
1651 #endif
1654 gpg_error_t pwmd_save2(pwm_t *pwm)
1656 #ifndef WITH_PINENTRY
1657 return GPG_ERR_NOT_IMPLEMENTED;
1658 #else
1659 return do_pwmd_save(pwm, 0, 1);
1660 #endif
1663 gpg_error_t pwmd_save(pwm_t *pwm)
1665 return do_pwmd_save(pwm, 0, 0);
1668 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1670 va_list ap;
1671 int n = va_arg(ap, int);
1672 char *arg1;
1673 gpg_error_t rc = 0;
1675 if (!pwm)
1676 return GPG_ERR_INV_ARG;
1678 va_start(ap, opt);
1680 switch (opt) {
1681 case PWMD_OPTION_INQUIRE_TOTAL:
1682 n = va_arg(ap, size_t);
1683 pwm->inquire_total = n;
1684 break;
1685 case PWMD_OPTION_STATUS_CB:
1686 pwm->status_func = va_arg(ap, pwmd_status_cb_t);
1687 break;
1688 case PWMD_OPTION_STATUS_DATA:
1689 pwm->status_data = va_arg(ap, void *);
1690 break;
1691 case PWMD_OPTION_PASSPHRASE_CB:
1692 pwm->passfunc = va_arg(ap, pwmd_passphrase_cb_t);
1693 break;
1694 case PWMD_OPTION_PASSPHRASE_DATA:
1695 pwm->passdata = va_arg(ap, void *);
1696 break;
1697 case PWMD_OPTION_PASSPHRASE:
1698 arg1 = va_arg(ap, char *);
1700 if (pwm->password)
1701 pwmd_free(pwm->password);
1703 pwm->password = arg1 ? pwmd_strdup(arg1) : NULL;
1704 break;
1705 case PWMD_OPTION_PINENTRY_TRIES:
1706 n = va_arg(ap, int);
1708 if (n <= 0) {
1709 va_end(ap);
1710 rc = GPG_ERR_INV_VALUE;
1712 else
1713 pwm->pinentry_tries = n;
1714 break;
1715 case PWMD_OPTION_PINENTRY_TIMEOUT:
1716 n = va_arg(ap, int);
1718 if (n < 0) {
1719 va_end(ap);
1720 rc = GPG_ERR_INV_VALUE;
1722 else
1723 pwm->pinentry_timeout = n;
1724 break;
1725 case PWMD_OPTION_PINENTRY_PATH:
1726 if (pwm->pinentry_path)
1727 pwmd_free(pwm->pinentry_path);
1729 pwm->pinentry_path = _expand_homedir(va_arg(ap, char *), NULL);
1730 break;
1731 case PWMD_OPTION_PINENTRY_TTY:
1732 arg1 = va_arg(ap, char *);
1734 if (pwm->pinentry_tty)
1735 pwmd_free(pwm->pinentry_tty);
1737 pwm->pinentry_tty = arg1 ? pwmd_strdup(arg1) : NULL;
1738 break;
1739 case PWMD_OPTION_PINENTRY_DISPLAY:
1740 if (pwm->pinentry_display)
1741 pwmd_free(pwm->pinentry_display);
1743 pwm->pinentry_display = pwmd_strdup(va_arg(ap, char *));
1744 break;
1745 case PWMD_OPTION_PINENTRY_TERM:
1746 arg1 = va_arg(ap, char *);
1748 if (pwm->pinentry_term)
1749 pwmd_free(pwm->pinentry_term);
1751 pwm->pinentry_term = arg1 ? pwmd_strdup(arg1) : NULL;
1752 break;
1753 case PWMD_OPTION_PINENTRY_TITLE:
1754 if (pwm->title)
1755 pwmd_free(pwm->title);
1757 pwm->title = _percent_escape(va_arg(ap, char *));
1758 break;
1759 case PWMD_OPTION_PINENTRY_PROMPT:
1760 if (pwm->prompt)
1761 pwmd_free(pwm->prompt);
1763 pwm->prompt = _percent_escape(va_arg(ap, char *));
1764 break;
1765 case PWMD_OPTION_PINENTRY_DESC:
1766 if (pwm->desc)
1767 pwmd_free(pwm->desc);
1769 pwm->desc = _percent_escape(va_arg(ap, char *));
1770 break;
1771 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1772 arg1 = va_arg(ap, char *);
1774 if (pwm->lcctype)
1775 pwmd_free(pwm->lcctype);
1777 pwm->lcctype = arg1 ? pwmd_strdup(arg1) : NULL;
1778 break;
1779 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1780 arg1 = va_arg(ap, char *);
1782 if (pwm->lcmessages)
1783 pwmd_free(pwm->lcmessages);
1785 pwm->lcmessages = arg1 ? pwmd_strdup(arg1) : NULL;
1786 break;
1787 case PWMD_OPTION_IP_VERSION:
1788 #ifdef WITH_TCP
1789 n = va_arg(ap, int);
1791 switch (n) {
1792 case PWMD_IP_ANY:
1793 case PWMD_IPV4:
1794 case PWMD_IPV6:
1795 pwm->prot = n;
1796 break;
1797 default:
1798 rc = GPG_ERR_INV_VALUE;
1799 break;
1802 va_end(ap);
1803 #else
1804 rc = GPG_ERR_NOT_IMPLEMENTED;
1805 #endif
1806 break;
1807 case PWMD_OPTION_KNOWNHOST_CB:
1808 #ifdef WITH_TCP
1809 pwm->kh_cb = va_arg(ap, pwmd_knownhost_cb_t);
1810 #else
1811 rc = GPG_ERR_NOT_IMPLEMENTED;
1812 #endif
1813 break;
1814 case PWMD_OPTION_KNOWNHOST_DATA:
1815 #ifdef WITH_TCP
1816 pwm->kh_data = va_arg(ap, void *);
1817 #else
1818 rc = GPG_ERR_NOT_IMPLEMENTED;
1819 #endif
1820 break;
1821 default:
1822 rc = GPG_ERR_UNKNOWN_OPTION;
1823 break;
1826 va_end(ap);
1827 return rc;
1830 gpg_error_t pwmd_get_fds(pwm_t *pwm, pwmd_fd_t *fds, int *n_fds)
1832 int in_total;
1833 int fd = 0;
1834 #ifdef WITH_TCP
1835 int afds[ARES_GETSOCK_MAXNUM];
1836 int got_sock = 0;
1837 int n, i;
1838 #endif
1840 if (!pwm || !fds || !n_fds || *n_fds <= 0)
1841 return GPG_ERR_INV_ARG;
1843 in_total = *n_fds;
1844 #ifdef WITH_TCP
1845 memset(afds, 0, sizeof(int)*ARES_GETSOCK_MAXNUM);
1846 #endif
1847 memset(fds, 0, sizeof(pwmd_fd_t)*in_total);
1848 *n_fds = 0;
1850 switch (pwm->cmd) {
1851 default:
1852 case ASYNC_CMD_NONE:
1853 case ASYNC_CMD_OPEN:
1854 case ASYNC_CMD_SAVE:
1855 #ifdef WITH_PINENTRY
1856 async1:
1857 #endif
1858 if (pwm->fd == -1)
1859 return GPG_ERR_INV_STATE;
1861 (*n_fds)++;
1862 fds[fd].fd = pwm->fd;
1863 fds[fd++].flags = PWMD_FD_READABLE;
1864 return 0;
1865 #ifdef WITH_PINENTRY
1866 case ASYNC_CMD_OPEN2:
1867 case ASYNC_CMD_SAVE2:
1868 /* The command has already completed (cached or new). */
1869 if (pwm->state == ASYNC_DONE)
1870 return 0;
1872 if (pwm->nb_fd == -1)
1873 return GPG_ERR_INV_STATE;
1875 (*n_fds)++;
1876 fds[fd].fd = pwm->nb_fd;
1877 fds[fd++].flags = PWMD_FD_READABLE;
1878 goto async1;
1879 #endif
1880 #ifdef WITH_TCP
1881 case ASYNC_CMD_DNS:
1882 if (!pwm->tcp_conn || !pwm->tcp_conn->chan)
1883 return GPG_ERR_INV_STATE;
1885 n = ares_getsock(pwm->tcp_conn->chan, afds, ARES_GETSOCK_MAXNUM);
1887 for (i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
1888 got_sock = 0;
1890 if (fd > in_total) {
1891 *n_fds = fd;
1892 return GPG_ERR_ERANGE;
1895 if (ARES_GETSOCK_READABLE(n, i)) {
1896 got_sock++;
1897 fds[fd].flags |= PWMD_FD_READABLE;
1900 if (ARES_GETSOCK_WRITABLE(n, i)) {
1901 got_sock++;
1902 fds[fd].flags |= PWMD_FD_WRITABLE;
1905 if (got_sock)
1906 fds[fd++].fd = afds[i];
1909 *n_fds = fd;
1910 return 0;
1911 case ASYNC_CMD_CONNECT:
1912 case ASYNC_CMD_HOSTKEY:
1913 if (!pwm->tcp_conn || pwm->tcp_conn->fd == -1)
1914 return GPG_ERR_INV_STATE;
1916 (*n_fds)++;
1917 fds[fd].fd = pwm->tcp_conn->fd;
1918 fds[fd++].flags = PWMD_FD_READABLE;
1919 return 0;
1920 #endif
1923 return GPG_ERR_INV_STATE;
1926 pwm_t *pwmd_new(const char *name)
1928 pwm_t *h = pwmd_calloc(1, sizeof(pwm_t));
1930 if (!h)
1931 return NULL;
1933 if (name) {
1934 h->name = pwmd_strdup(name);
1936 if (!h->name) {
1937 pwmd_free(h);
1938 return NULL;
1942 reset_handle(h);
1943 h->pinentry_timeout = -30;
1944 h->pinentry_tries = 3;
1945 #ifdef WITH_TCP
1946 h->prot = PWMD_IP_ANY;
1947 #endif
1949 if (ttyname(STDOUT_FILENO)) {
1950 char buf[256];
1952 ttyname_r(STDOUT_FILENO, buf, sizeof(buf));
1953 h->pinentry_tty = pwmd_strdup(buf);
1955 if (!h->pinentry_tty)
1956 goto fail;
1959 if (getenv("TERM") && h->pinentry_tty) {
1960 h->pinentry_term = pwmd_strdup(getenv("TERM"));
1962 if (!h->pinentry_term)
1963 goto fail;
1966 if (getenv("DISPLAY")) {
1967 h->pinentry_display = pwmd_strdup(getenv("DISPLAY"));
1969 if (!h->pinentry_display)
1970 goto fail;
1973 return h;
1975 fail:
1976 pwmd_close(h);
1977 return NULL;
1980 void pwmd_free(void *ptr)
1982 _xfree(ptr);
1985 void *pwmd_malloc(size_t size)
1987 return _xmalloc(size);
1990 void *pwmd_calloc(size_t nmemb, size_t size)
1992 return _xcalloc(nmemb, size);
1995 void *pwmd_realloc(void *ptr, size_t size)
1997 return _xrealloc(ptr, size);
2000 char *pwmd_strdup(const char *str)
2002 return _xstrdup(str);
2005 char *pwmd_strdup_printf(const char *fmt, ...)
2007 va_list ap, ap2;
2008 int len;
2009 char *buf;
2011 if (!fmt)
2012 return NULL;
2014 va_start(ap, fmt);
2015 va_copy(ap2, ap);
2016 len = vsnprintf(NULL, 0, fmt, ap);
2017 va_end(ap);
2018 buf = pwmd_malloc(++len);
2020 if (buf)
2021 vsnprintf(buf, len, fmt, ap2);
2023 va_end(ap2);
2024 return buf;
2027 gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result,
2028 pwmd_pinentry_t which)
2030 #ifndef WITH_PINENTRY
2031 return GPG_ERR_NOT_IMPLEMENTED;
2032 #else
2033 return _pwmd_getpin(pwm, filename, result, which);
2034 #endif