Return GPG_ERR_INV_ARG if the inquire callback doesn't have sane values.
[libpwmd.git] / src / libpwmd.c
blobdbb961b2ecf28839defb1b8949d1ef068f900ef8
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 gpg_err_init();
122 assuan_set_malloc_hooks(pwmd_malloc, pwmd_realloc, pwmd_free);
123 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
124 initialized = 1;
125 return 0;
128 gpg_error_t _connect_finalize(pwm_t *pwm)
130 int active[2];
131 int n = assuan_get_active_fds(pwm->ctx, 0, active, N_ARRAY(active));
132 gpg_error_t rc;
134 if (n <= 0)
135 return GPG_ERR_EBADFD;
137 pwm->fd = active[0];
138 #ifdef WITH_PINENTRY
139 pwm->pid = -1;
140 #endif
141 assuan_set_pointer(pwm->ctx, pwm);
143 #ifdef WITH_TCP
144 // Until X11 forwarding is supported, disable the remote pwmd pinentry.
145 if (pwm->tcp_conn) {
146 pwm->tcp_conn->state = SSH_NONE;
147 rc = pwmd_command(pwm, NULL, "SET ENABLE_PINENTRY=0");
149 if (rc)
150 return rc;
152 #endif
154 if (pwm->name) {
155 rc = pwmd_command(pwm, NULL, "SET NAME=%s", pwm->name);
157 if (rc)
158 return rc;
161 return 0;
164 static gpg_error_t _pwmd_connect_url(pwm_t *pwm, const char *url, int async)
166 char *p = (char *)url;
167 gpg_error_t rc;
169 if (!pwm)
170 return GPG_ERR_INV_ARG;
172 if (!p || !strncmp(p, "file://", 7) || !strncmp(p, "local://", 8)) {
173 if (p) {
174 if (!strncmp(p, "file://", 7))
175 p += 7;
176 else
177 p += 8;
180 goto connect_uds;
182 else if (!strncmp(p, "ssh://", 6) || !strncmp(p, "ssh6://", 7) ||
183 !strncmp(p, "ssh4://", 7)) {
184 #ifndef WITH_TCP
185 return GPG_ERR_NOT_IMPLEMENTED;
186 #else
187 char *host = NULL;
188 int port = -1;
189 char *identity = NULL;
190 char *known_hosts = NULL;
191 char *username = NULL;
193 if (!strncmp(p, "ssh6://", 7)) {
194 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV6);
195 p += 7;
197 else if (!strncmp(p, "ssh4://", 7)) {
198 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV4);
199 p += 7;
201 else {
202 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IP_ANY);
203 p += 6;
206 if (rc)
207 return rc;
209 rc = _parse_ssh_url(p, &host, &port, &username, &identity,
210 &known_hosts);
212 if (rc)
213 goto fail;
215 if (async)
216 rc = pwmd_ssh_connect_async(pwm, host, port, identity, username,
217 known_hosts);
218 else
219 rc = pwmd_ssh_connect(pwm, host, port, identity, username,
220 known_hosts);
222 fail:
223 if (host)
224 pwmd_free(host);
226 if (username)
227 pwmd_free(username);
229 if (identity)
230 pwmd_free(identity);
232 if (known_hosts)
233 pwmd_free(known_hosts);
235 return rc;
236 #endif
239 connect_uds:
240 rc = pwmd_connect(pwm, p);
241 pwm->state = ASYNC_DONE;
242 return rc;
245 gpg_error_t pwmd_connect_url(pwm_t *pwm, const char *url)
247 return _pwmd_connect_url(pwm, url, 0);
250 gpg_error_t pwmd_connect_url_async(pwm_t *pwm, const char *url)
252 return _pwmd_connect_url(pwm, url, 1);
255 gpg_error_t pwmd_connect(pwm_t *pwm, const char *path)
257 char *socketpath = NULL;
258 assuan_context_t ctx;
259 struct passwd pw;
260 char *pwbuf;
261 gpg_error_t rc;
263 if (!pwm)
264 return GPG_ERR_INV_ARG;
266 pwbuf = _getpwuid(&pw);
268 if (!pwbuf)
269 return gpg_error_from_errno(errno);
271 if (!path || !*path)
272 socketpath = pwmd_strdup_printf("%s/.pwmd/socket", pw.pw_dir);
273 else
274 socketpath = _expand_homedir((char *)path, &pw);
276 pwmd_free(pwbuf);
278 if (!socketpath)
279 return gpg_error_from_errno(ENOMEM);
281 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
282 pwmd_free(socketpath);
284 if (rc)
285 return gpg_err_code(rc);
287 pwm->ctx = ctx;
288 return _connect_finalize(pwm);
291 static void disconnect(pwm_t *pwm)
293 if (!pwm || !pwm->ctx)
294 return;
296 assuan_disconnect(pwm->ctx);
297 pwm->ctx = NULL;
298 pwm->fd = -1;
301 void pwmd_close(pwm_t *pwm)
303 if (!pwm)
304 return;
306 disconnect(pwm);
308 if (pwm->password)
309 pwmd_free(pwm->password);
311 if (pwm->title)
312 pwmd_free(pwm->title);
314 if (pwm->desc)
315 pwmd_free(pwm->desc);
317 if (pwm->prompt)
318 pwmd_free(pwm->prompt);
320 if (pwm->pinentry_tty)
321 pwmd_free(pwm->pinentry_tty);
323 if (pwm->pinentry_display)
324 pwmd_free(pwm->pinentry_display);
326 if (pwm->pinentry_term)
327 pwmd_free(pwm->pinentry_term);
329 if (pwm->lcctype)
330 pwmd_free(pwm->lcctype);
332 if (pwm->lcmessages)
333 pwmd_free(pwm->lcmessages);
335 if (pwm->filename)
336 pwmd_free(pwm->filename);
338 if (pwm->name)
339 pwmd_free(pwm->name);
341 #ifdef WITH_TCP
342 if (pwm->tcp_conn)
343 _free_ssh_conn(pwm->tcp_conn);
344 #endif
346 #ifdef WITH_PINENTRY
347 if (pwm->pctx)
348 _pinentry_disconnect(pwm);
349 #endif
351 pwmd_free(pwm);
354 static gpg_error_t do_async_command(pwm_t *pwm, char **result)
356 pwmd_async_t s;
357 gpg_error_t rc;
359 do {
360 s = pwmd_process(pwm, &rc, result);
362 if (s != ASYNC_DONE) {
363 #ifdef WITH_LIBPTH
364 pth_usleep(50000);
365 #else
366 usleep(50000);
367 #endif
369 } while (s != ASYNC_DONE);
371 return rc;
374 gpg_error_t pwmd_ssh_connect_async(pwm_t *pwm, const char *host, int port,
375 const char *identity, const char *user, const char *known_hosts)
377 #ifndef WITH_TCP
378 return GPG_ERR_NOT_IMPLEMENTED;
379 #else
380 return _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
381 known_hosts, ASYNC_CMD_CONNECT);
382 #endif
385 gpg_error_t pwmd_ssh_connect(pwm_t *pwm, const char *host, int port,
386 const char *identity, const char *user, const char *known_hosts)
388 #ifndef WITH_TCP
389 return GPG_ERR_NOT_IMPLEMENTED;
390 #else
391 gpg_error_t rc;
393 rc = _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
394 known_hosts, ASYNC_CMD_CONNECT);
395 return rc || do_async_command(pwm, NULL);
396 #endif
399 gpg_error_t pwmd_get_hostkey(pwm_t *pwm, const char *host, int port,
400 char **result)
402 #ifndef WITH_TCP
403 return GPG_ERR_NOT_IMPLEMENTED;
404 #else
405 gpg_error_t rc;
407 rc = _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
408 ASYNC_CMD_HOSTKEY);
410 return rc || do_async_command(pwm, result);
411 #endif
414 gpg_error_t pwmd_get_hostkey_async(pwm_t *pwm, const char *host, int port)
416 #ifndef WITH_TCP
417 return GPG_ERR_NOT_IMPLEMENTED;
418 #else
419 return _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
420 ASYNC_CMD_HOSTKEY);
421 #endif
424 static int inquire_realloc_cb(void *data, const void *buffer, size_t len)
426 membuf_t *mem = (membuf_t *)data;
427 void *p;
429 if (!buffer)
430 return 0;
432 if ((p = pwmd_realloc(mem->buf, mem->len + len)) == NULL)
433 return gpg_error_from_errno(ENOMEM);
435 mem->buf = p;
436 memcpy((char *)mem->buf + mem->len, buffer, len);
437 mem->len += len;
438 return 0;
441 static int inquire_cb(void *data, const char *keyword)
443 pwm_t *pwm = (pwm_t *)data;
444 gpg_error_t rc = 0;
445 int is_eagain = 0;
447 /* Shouldn't get this far without a callback. */
448 if (!pwm->inquire_func)
449 return GPG_ERR_INV_ARG;
451 for (;;) {
452 char *result = NULL;
453 size_t len;
454 gpg_error_t arc;
456 rc = pwm->inquire_func(pwm->inquire_data, keyword, rc, &result, &len);
457 rc = gpg_err_code(rc);
459 if (rc == GPG_ERR_EOF || !rc) {
460 if (len <= 0 && !result) {
461 rc = 0;
462 break;
464 else if ((len <= 0 && result) || (len && !result)) {
465 rc = GPG_ERR_INV_ARG;
466 break;
469 eagain:
470 is_eagain = 0;
471 arc = assuan_send_data(pwm->ctx, result, len);
472 arc = gpg_err_code(arc);
474 if (rc == GPG_ERR_EOF) {
475 rc = arc;
476 break;
479 rc = arc;
481 if (rc == GPG_ERR_EAGAIN) {
482 rc = 0;
483 is_eagain = 1;
484 goto process;
487 else if (rc)
488 break;
490 if (!rc) {
491 pwm->inquire_sent += len;
493 if (pwm->status_func) {
494 char buf[ASSUAN_LINELENGTH];
496 snprintf(buf, sizeof(buf), "XFER %u %u", pwm->inquire_sent,
497 pwm->inquire_total);
498 rc = pwm->status_func(pwm->status_data, buf);
500 if (rc)
501 continue;
504 process:
505 rc = _pwmd_process(pwm);
507 if (rc == GPG_ERR_EAGAIN)
508 rc = 0;
511 if (!rc && is_eagain)
512 goto eagain;
515 return gpg_err_code(rc);
518 static gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, ...)
520 char *buf;
521 gpg_error_t rc;
522 va_list ap;
523 int len;
525 if (pwm->state == ASYNC_DONE)
526 pwm->state = ASYNC_INIT;
528 if (pwm->state != ASYNC_INIT)
529 return GPG_ERR_INV_STATE;
531 buf = pwmd_malloc(ASSUAN_LINELENGTH+1);
533 if (!buf)
534 return gpg_error_from_errno(ENOMEM);
536 va_start(ap, cmd);
537 len = vsnprintf(buf, ASSUAN_LINELENGTH+1, cmd, ap);
538 va_end(ap);
540 if (len >= ASSUAN_LINELENGTH+1) {
541 pwmd_free(buf);
542 return GPG_ERR_LINE_TOO_LONG;
545 rc = assuan_write_line(pwm->ctx, buf);
546 pwmd_free(buf);
548 if (!rc)
549 pwm->state = ASYNC_PROCESS;
551 return gpg_err_code(rc);
554 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
556 char *p = NULL;
557 const char *f = NULL;
558 gpg_error_t rc;
560 if (!pwm || !filename)
561 return GPG_ERR_INV_ARG;
563 if (!pwm->ctx)
564 return GPG_ERR_INV_STATE;
566 if (pwm->cmd != ASYNC_CMD_NONE)
567 return GPG_ERR_ASS_NESTED_COMMANDS;
569 if (pwm->lastcmd == ASYNC_CMD_NONE) {
570 pwm->pin_try = 0;
572 if (pwm->filename)
573 pwmd_free(pwm->filename);
575 pwm->filename = pwmd_strdup(filename);
577 if (!pwm->filename)
578 return gpg_error_from_errno(ENOMEM);
580 gpg_error_t rc = send_pinentry_options(pwm);
582 if (rc)
583 return rc;
585 rc = get_custom_passphrase(pwm, &p);
587 if (rc && rc != GPG_ERR_NO_DATA)
588 return rc;
590 f = filename;
592 #ifdef WITH_PINENTRY
593 else if (pwm->lastcmd == ASYNC_CMD_OPEN2) {
594 p = pwm->_password;
595 f = pwm->filename;
597 #endif
598 else if (pwm->lastcmd == ASYNC_CMD_OPEN) {
599 rc = set_pinentry_retry(pwm);
601 if (rc)
602 return rc;
604 p = pwm->password;
605 f = filename;
607 else
608 return GPG_ERR_INV_STATE;
610 pwm->cmd = ASYNC_CMD_OPEN;
611 return do_nb_command(pwm, "OPEN %s %s", f, p ? p : "");
614 gpg_error_t pwmd_save_async(pwm_t *pwm)
616 char *p = NULL;
618 if (!pwm)
619 return GPG_ERR_INV_ARG;
621 if (!pwm->ctx)
622 return GPG_ERR_INV_STATE;
624 if (pwm->cmd != ASYNC_CMD_NONE)
625 return GPG_ERR_ASS_NESTED_COMMANDS;
627 if (pwm->lastcmd != ASYNC_CMD_SAVE2) {
628 gpg_error_t rc = send_pinentry_options(pwm);
630 if (rc)
631 return rc;
633 rc = get_custom_passphrase(pwm, &p);
635 if (rc && rc != GPG_ERR_NO_DATA)
636 return rc;
638 #ifdef WITH_PINENTRY
639 else
640 p = pwm->_password;
641 #endif
643 pwm->cmd = ASYNC_CMD_SAVE;
644 return do_nb_command(pwm, "SAVE %s", p ? p : "");
647 static gpg_error_t parse_assuan_line(pwm_t *pwm)
649 gpg_error_t rc;
650 char *line;
651 size_t len;
653 rc = assuan_read_line(pwm->ctx, &line, &len);
655 if (!rc) {
656 if (line[0] == 'O' && line[1] == 'K' &&
657 (line[2] == 0 || line[2] == ' ')) {
658 pwm->state = ASYNC_DONE;
660 else if (line[0] == '#') {
662 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
663 if (pwm->status_func) {
664 rc = pwm->status_func(pwm->status_data,
665 line[1] == 0 ? line+1 : line+2);
668 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
669 (line[3] == 0 || line[3] == ' ')) {
670 line += 4;
671 rc = atoi(line);
672 pwm->state = ASYNC_DONE;
676 return gpg_err_code(rc);
679 gpg_error_t pwmd_pending_line(pwm_t *pwm)
681 if (!pwm)
682 return GPG_ERR_INV_ARG;
684 if (!pwm->ctx)
685 return GPG_ERR_INV_STATE;
687 return assuan_pending_line(pwm->ctx) ? 0 : GPG_ERR_NO_DATA;
690 static pwmd_async_t reset_async(pwm_t *pwm, int done)
692 pwm->state = ASYNC_INIT;
693 pwm->cmd = pwm->lastcmd = ASYNC_CMD_NONE;
695 #ifdef WITH_PINENTRY
696 if (pwm->nb_fd != -1) {
697 close(pwm->nb_fd);
698 pwm->nb_fd = -1;
701 if (pwm->_password) {
702 pwmd_free(pwm->_password);
703 pwm->_password = NULL;
705 #endif
706 #ifdef WITH_TCP
707 if (pwm->tcp_conn)
708 pwm->tcp_conn->rc = 0;
710 if (done && pwm->tcp_conn) {
711 _free_ssh_conn(pwm->tcp_conn);
712 pwm->tcp_conn = NULL;
714 #endif
716 return ASYNC_DONE;
720 * Used for processing status messages when not in an async command and for
721 * waiting for the result from pwmd_open_async() and pwmd_save_async().
723 static gpg_error_t _pwmd_process(pwm_t *pwm)
725 gpg_error_t rc = 0;
726 fd_set fds;
727 struct timeval tv = {0, 0};
728 int n;
730 FD_ZERO(&fds);
731 FD_SET(pwm->fd, &fds);
732 #ifdef WITH_LIBPTH
733 n = pth_select(pwm->fd+1, &fds, NULL, NULL, &tv);
734 #else
735 n = select(pwm->fd+1, &fds, NULL, NULL, &tv);
736 #endif
738 if (n == -1)
739 return gpg_error_from_syserror();
741 if (n > 0) {
742 if (FD_ISSET(pwm->fd, &fds))
743 rc = parse_assuan_line(pwm);
746 while (!rc && assuan_pending_line(pwm->ctx))
747 rc = parse_assuan_line(pwm);
749 return gpg_err_code(rc);
752 static void reset_handle(pwm_t *h)
754 h->fd = -1;
755 #ifdef WITH_PINENTRY
756 if (h->pctx)
757 _pinentry_disconnect(h);
759 h->nb_fd = -1;
760 #endif
761 h->pin_try = 0;
762 reset_async(h, 0);
765 gpg_error_t pwmd_disconnect(pwm_t *pwm)
767 if (!pwm)
768 return GPG_ERR_INV_ARG;
770 #ifdef WITH_TCP
771 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
772 #else
773 if (pwm->fd == -1)
774 #endif
775 return GPG_ERR_INV_STATE;
777 if (pwm->fd != 1)
778 disconnect(pwm);
779 #ifdef WITH_TCP
780 else
781 _ssh_disconnect(pwm);
782 #endif
784 reset_handle(pwm);
785 return 0;
788 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc, char **result)
790 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
791 fd_set fds;
792 int n;
793 struct timeval tv = {0, 0};
794 #endif
796 if (result)
797 *result = NULL;
799 if (!rc)
800 return GPG_ERR_INV_ARG;
802 *rc = 0;
804 if (!pwm) {
805 *rc = GPG_ERR_INV_ARG;
806 return ASYNC_DONE;
808 else if (!pwm->ctx) {
809 switch (pwm->cmd) {
810 default:
811 *rc = GPG_ERR_INV_STATE;
812 return ASYNC_DONE;
813 #ifdef WITH_TCP
814 case ASYNC_CMD_DNS:
815 case ASYNC_CMD_CONNECT:
816 case ASYNC_CMD_HOSTKEY:
817 break;
818 #endif
822 /* When not in a command, this will let libassuan process status messages
823 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
824 * descriptor returned by pwmd_get_fd() to determine when this should be
825 * called or call pwmd_pending_line() to determine whether a buffered line
826 * needs to be processed. */
827 if (pwm->cmd == ASYNC_CMD_NONE) {
828 *rc = _pwmd_process(pwm);
829 return ASYNC_DONE;
832 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
833 if (pwm->state == ASYNC_DONE) {
834 *rc = _pwmd_process(pwm);
835 return reset_async(pwm, 0);
838 if (pwm->state != ASYNC_PROCESS) {
839 *rc = GPG_ERR_INV_STATE;
840 return ASYNC_DONE;
843 #ifdef WITH_TCP
844 if (pwm->cmd == ASYNC_CMD_DNS) {
845 fd_set rfds, wfds;
847 if (pwm->tcp_conn->rc) {
848 *rc = pwm->tcp_conn->rc;
849 return reset_async(pwm, 1);
852 FD_ZERO(&rfds);
853 FD_ZERO(&wfds);
854 n = ares_fds(pwm->tcp_conn->chan, &rfds, &wfds);
856 /* Shouldn't happen. */
857 if (!n)
858 return pwm->state;
860 #ifdef WITH_LIBPTH
861 n = pth_select(n, &rfds, &wfds, NULL, &tv);
862 #else
863 n = select(n, &rfds, &wfds, NULL, &tv);
864 #endif
866 if (n < 0) {
867 *rc = gpg_error_from_syserror();
868 return reset_async(pwm, 1);
871 if (n > 0)
872 ares_process(pwm->tcp_conn->chan, &rfds, &wfds);
874 return pwm->state;
876 else if (pwm->cmd == ASYNC_CMD_CONNECT) {
877 if (pwm->tcp_conn->rc == GPG_ERR_EINPROGRESS) {
878 int ret;
879 socklen_t len = sizeof(int);
881 FD_ZERO(&fds);
882 FD_SET(pwm->tcp_conn->fd, &fds);
883 #ifdef WITH_LIBPTH
884 n = pth_select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
885 #else
886 n = select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
887 #endif
889 if (!n || !FD_ISSET(pwm->tcp_conn->fd, &fds))
890 return pwm->state;
891 else if (n == -1) {
892 *rc = gpg_error_from_syserror();
893 return reset_async(pwm, 1);
896 ret = getsockopt(pwm->tcp_conn->fd, SOL_SOCKET, SO_ERROR, &n, &len);
898 if (ret || n) {
899 *rc = ret ? gpg_error_from_syserror() : gpg_error_from_errno(n);
900 return reset_async(pwm, 1);
903 pwm->tcp_conn->state = SSH_NONE;
904 pwm->tcp_conn->rc = 0;
905 *rc = _setup_ssh_session(pwm);
907 if (*rc && *rc != GPG_ERR_EAGAIN)
908 return reset_async(pwm, 1);
910 else if (pwm->tcp_conn->rc) {
911 *rc = pwm->tcp_conn->rc;
912 return reset_async(pwm, 1);
915 switch (pwm->tcp_conn->state) {
916 case SSH_INIT:
917 *rc = _setup_ssh_init(pwm);
918 break;
919 case SSH_AUTHLIST:
920 *rc = _setup_ssh_authlist(pwm);
921 break;
922 case SSH_AUTH:
923 *rc = _setup_ssh_auth(pwm);
924 break;
925 case SSH_CHANNEL:
926 *rc = _setup_ssh_channel(pwm);
927 break;
928 case SSH_SHELL:
929 *rc = _setup_ssh_shell(pwm);
930 break;
931 default:
932 break;
935 if (*rc == GPG_ERR_EAGAIN) {
936 *rc = 0;
937 return ASYNC_PROCESS;
940 if (!*rc) {
941 switch (pwm->tcp_conn->cmd) {
942 case ASYNC_CMD_HOSTKEY:
943 *result = pwmd_strdup(pwm->tcp_conn->hostkey);
945 if (!*result)
946 *rc = GPG_ERR_ENOMEM;
947 break;
948 default:
949 break;
953 return reset_async(pwm, *rc ? 1 : 0);
955 #endif
957 #ifdef WITH_PINENTRY
958 if (pwm->cmd == ASYNC_CMD_OPEN2 || pwm->cmd == ASYNC_CMD_SAVE2) {
959 int status;
961 if (pwm->nb_fd == -1) {
962 *rc = GPG_ERR_INV_STATE;
963 return reset_async(pwm, 0);
966 FD_ZERO(&fds);
967 FD_SET(pwm->nb_fd, &fds);
968 FD_SET(pwm->fd, &fds);
969 #ifdef WITH_LIBPTH
970 n = pth_select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
971 #else
972 n = select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
973 #endif
974 if (n < 0) {
975 *rc = gpg_error_from_syserror();
976 return reset_async(pwm, 0);
979 if (n > 0 && FD_ISSET(pwm->nb_fd, &fds)) {
980 pwmd_nb_status_t nb;
981 #ifdef WITH_LIBPTH
982 size_t len = pth_read(pwm->nb_fd, &nb, sizeof(nb));
983 #else
984 size_t len = read(pwm->nb_fd, &nb, sizeof(nb));
985 #endif
986 waitpid(pwm->nb_pid, &status, WNOHANG);
988 if (len != sizeof(nb)) {
989 memset(&nb, 0, sizeof(pwmd_nb_status_t));
990 *rc = gpg_error_from_syserror();
991 return reset_async(pwm, 0);
994 *rc = nb.error;
996 if (*rc)
997 return reset_async(pwm, 0);
999 /* Since the non-blocking pinentry returned a success, do a
1000 * non-blocking OPEN or SAVE. */
1001 pwmd_async_cmd_t c = pwm->cmd;
1002 reset_async(pwm, 0);
1003 pwm->_password = pwmd_strdup(nb.password);
1004 memset(&nb, 0, sizeof(pwmd_nb_status_t));
1005 pwm->lastcmd = c;
1007 if (!pwm->_password) {
1008 *rc = gpg_error_from_errno(ENOMEM);
1009 return reset_async(pwm, 0);
1012 if (c == ASYNC_CMD_SAVE2)
1013 *rc = pwmd_save_async(pwm);
1014 else
1015 *rc = pwmd_open_async(pwm, pwm->filename);
1017 if (*rc) {
1018 reset_async(pwm, 0);
1019 return ASYNC_DONE;
1022 return ASYNC_PROCESS;
1025 /* Fall through so status messages can be processed during the
1026 * pinentry. */
1028 #endif
1030 if (pwm->fd < 0) {
1031 *rc = GPG_ERR_INV_STATE;
1032 return reset_async(pwm, 0);
1035 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
1036 * retries. */
1037 *rc = _pwmd_process(pwm);
1039 if (*rc && *rc != GPG_ERR_INV_PASSPHRASE)
1040 return reset_async(pwm, 0);
1042 if (pwm->cmd == ASYNC_CMD_OPEN &&
1043 *rc == GPG_ERR_INV_PASSPHRASE &&
1044 #ifdef WITH_TCP
1045 (!pwm->tcp_conn || (pwm->tcp_conn && pwm->lastcmd == ASYNC_CMD_OPEN2)) &&
1046 #endif
1047 ++pwm->pin_try < pwm->pinentry_tries) {
1048 if (!get_custom_passphrase(pwm, NULL))
1049 goto done;
1051 #ifdef WITH_PINENTRY
1052 if (pwm->_password) {
1053 reset_async(pwm, 0);
1054 pwm->lastcmd = ASYNC_CMD_OPEN2;
1055 *rc = pwmd_open_async2(pwm, pwm->filename);
1057 else {
1058 #endif
1059 reset_async(pwm, 0);
1060 pwm->lastcmd = ASYNC_CMD_OPEN;
1061 *rc = pwmd_open_async(pwm, pwm->filename);
1062 #ifdef WITH_PINENTRY
1064 #endif
1067 done:
1068 if (*rc || pwm->state == ASYNC_DONE)
1069 return reset_async(pwm, 0);
1071 return pwm->state;
1074 gpg_error_t _assuan_command(pwm_t *pwm, assuan_context_t ctx,
1075 char **result, const char *cmd)
1077 membuf_t data;
1078 gpg_error_t rc;
1080 if (!cmd || !*cmd)
1081 return GPG_ERR_INV_ARG;
1083 if (strlen(cmd) >= ASSUAN_LINELENGTH+1)
1084 return GPG_ERR_LINE_TOO_LONG;
1086 data.len = 0;
1087 data.buf = NULL;
1088 rc = assuan_transact(ctx, cmd, inquire_realloc_cb, &data,
1089 #ifdef WITH_QUALITY
1090 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1091 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1092 #else
1093 inquire_cb, pwm,
1094 #endif
1095 pwm->status_func, pwm->status_data);
1097 if (rc) {
1098 if (data.buf) {
1099 pwmd_free(data.buf);
1100 data.buf = NULL;
1103 else {
1104 if (data.buf) {
1105 inquire_realloc_cb(&data, "", 1);
1107 if (!result) {
1108 pwmd_free(data.buf);
1109 rc = GPG_ERR_INV_ARG;
1111 else
1112 *result = (char *)data.buf;
1116 return gpg_err_code(rc);
1119 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_cb_t fn,
1120 void *data)
1122 if (!pwm || !cmd || !fn)
1123 return GPG_ERR_INV_ARG;
1125 if (!pwm->ctx)
1126 return GPG_ERR_INV_STATE;
1128 pwm->inquire_func = fn;
1129 pwm->inquire_data = data;
1130 pwm->inquire_sent = 0;
1131 return _assuan_command(pwm, pwm->ctx, NULL, cmd);
1134 gpg_error_t pwmd_command_ap(pwm_t *pwm, char **result, const char *cmd,
1135 va_list ap)
1137 char *buf;
1138 size_t len;
1139 va_list ap2;
1141 if (!pwm || !cmd)
1142 return GPG_ERR_INV_ARG;
1144 if (!pwm->ctx)
1145 return GPG_ERR_INV_STATE;
1148 * C99 allows the dst pointer to be null which will calculate the length
1149 * of the would-be result and return it.
1151 va_copy(ap2, ap);
1152 len = vsnprintf(NULL, 0, cmd, ap)+1;
1153 buf = (char *)pwmd_malloc(len);
1155 if (!buf) {
1156 va_end(ap2);
1157 return gpg_error_from_errno(ENOMEM);
1160 len = vsnprintf(buf, len, cmd, ap2);
1161 va_end(ap2);
1163 if (buf[strlen(buf)-1] == '\n')
1164 buf[strlen(buf)-1] = 0;
1166 if (buf[strlen(buf)-1] == '\r')
1167 buf[strlen(buf)-1] = 0;
1169 gpg_error_t rc = _assuan_command(pwm, pwm->ctx, result, buf);
1170 pwmd_free(buf);
1171 return rc;
1174 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
1176 va_list ap;
1178 if (!pwm || !cmd)
1179 return GPG_ERR_INV_ARG;
1181 if (!pwm->ctx)
1182 return GPG_ERR_INV_STATE;
1184 if (result)
1185 *result = NULL;
1187 va_start(ap, cmd);
1188 gpg_error_t rc = pwmd_command_ap(pwm, result, cmd, ap);
1189 va_end(ap);
1190 return rc;
1193 static gpg_error_t send_pinentry_options(pwm_t *pwm)
1195 gpg_error_t rc;
1197 if (pwm->pinentry_path) {
1198 rc = pwmd_command(pwm, NULL, "SET PINENTRY_PATH=%s",
1199 pwm->pinentry_path);
1201 if (rc)
1202 return rc;
1205 if (pwm->pinentry_tty) {
1206 rc = pwmd_command(pwm, NULL, "SET TTYNAME=%s", pwm->pinentry_tty);
1208 if (rc)
1209 return rc;
1212 if (pwm->pinentry_term) {
1213 rc = pwmd_command(pwm, NULL, "SET TTYTYPE=%s", pwm->pinentry_term);
1215 if (rc)
1216 return rc;
1219 if (pwm->pinentry_display) {
1220 rc = pwmd_command(pwm, NULL, "SET DISPLAY=%s",
1221 pwm->pinentry_display);
1223 if (rc)
1224 return rc;
1227 if (pwm->title) {
1228 rc = pwmd_command(pwm, NULL, "SET TITLE=%s", pwm->title);
1230 if (rc)
1231 return rc;
1234 if (pwm->desc) {
1235 rc = pwmd_command(pwm, NULL, "SET DESC=%s", pwm->desc);
1237 if (rc)
1238 return rc;
1241 if (pwm->prompt) {
1242 rc = pwmd_command(pwm, NULL, "SET PROMPT=%s", pwm->prompt);
1244 if (rc)
1245 return rc;
1248 if (pwm->lcctype) {
1249 rc = pwmd_command(pwm, NULL, "SET LC_CTYPE=%s", pwm->lcctype);
1251 if (rc)
1252 return rc;
1255 if (pwm->lcmessages) {
1256 rc = pwmd_command(pwm, NULL, "SET LC_MESSAGES=%s", pwm->lcmessages);
1258 if (rc)
1259 return rc;
1262 if (pwm->pinentry_timeout >= 0 && !pwm->pin_try) {
1263 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=%i",
1264 pwm->pinentry_timeout);
1266 if (rc)
1267 return rc;
1270 return 0;
1273 gpg_error_t pwmd_socket_type(pwm_t *pwm, pwmd_socket_t *result)
1275 if (!pwm || !result)
1276 return GPG_ERR_INV_ARG;
1278 #ifdef WITH_TCP
1279 if ((pwm->fd == -1 && !pwm->tcp_conn) ||
1280 (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1))
1281 #else
1282 if (pwm->fd == -1)
1283 #endif
1284 return GPG_ERR_INV_STATE;
1286 #ifdef WITH_TCP
1287 *result = pwm->tcp_conn ? PWMD_SOCKET_SSH : PWMD_SOCKET_LOCAL;
1288 #else
1289 *result = PWMD_SOCKET_LOCAL;
1290 #endif
1291 return 0;
1294 static gpg_error_t set_pinentry_retry(pwm_t *pwm)
1296 gpg_error_t rc = 0;
1298 if (pwm->pin_try == 1) {
1299 rc = pwmd_command(pwm, NULL, "SET TITLE=%s",
1300 N_("Invalid passphrase, please try again."));
1302 if (rc)
1303 return rc;
1305 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=0");
1308 return rc;
1311 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result)
1313 gpg_error_t rc = GPG_ERR_NO_DATA;
1315 if (result)
1316 *result = NULL;
1317 else {
1318 if (pwm->password || pwm->passfunc)
1319 return 0;
1322 if (pwm->password) {
1323 rc = 0;
1324 *result = pwm->password;
1326 else if (pwm->passfunc)
1327 rc = pwm->passfunc(pwm->passdata, result);
1329 return rc;
1332 static gpg_error_t do_pwmd_open(pwm_t *pwm, const char *filename, int nb,
1333 int local_pinentry)
1335 char *result = NULL;
1336 char *password = NULL;
1337 gpg_error_t rc;
1339 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1340 pwm->pin_try = 0;
1342 if (!pwm || !filename || !*filename)
1343 return GPG_ERR_INV_ARG;
1345 if (!pwm->ctx)
1346 return GPG_ERR_INV_STATE;
1349 * Avoid calling pinentry if the password is cached on the server or if
1350 * this is a new file.
1352 rc = pwmd_command(pwm, &result, "ISCACHED %s", filename);
1354 if (rc == GPG_ERR_ENOENT)
1355 goto gotpassword;
1357 if (rc && rc != GPG_ERR_NOT_FOUND)
1358 return rc;
1360 if (rc == GPG_ERR_NOT_FOUND) {
1361 rc = get_custom_passphrase(pwm, &password);
1363 if (rc && rc != GPG_ERR_NO_DATA)
1364 return rc;
1365 else if (rc == GPG_ERR_NO_DATA)
1366 rc = GPG_ERR_NOT_FOUND;
1367 else
1368 goto gotpassword;
1371 #ifdef WITH_PINENTRY
1372 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1373 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1374 if (!pwm->pin_try) {
1375 rc = pwmd_command(pwm, NULL, "SET ENABLE_PINENTRY=0");
1377 if (rc)
1378 return rc;
1381 rc = _pinentry_open(pwm, filename, &password, nb);
1383 /* pwmd_process() should be called if using a non-blocking local
1384 * pinentry. */
1385 if (rc || (!rc && nb))
1386 return rc;
1388 #endif
1390 gotpassword:
1391 reset_async(pwm, 0);
1393 #ifdef WITH_TCP
1394 if (!local_pinentry && !pwm->tcp_conn && !pwm->pin_try) {
1395 #else
1396 if (!local_pinentry && !pwm->pin_try) {
1397 #endif
1398 rc = send_pinentry_options(pwm);
1400 if (rc)
1401 return rc;
1404 rc = pwmd_command(pwm, NULL, "OPEN %s %s", filename,
1405 password ? password : "");
1408 * Keep the user defined password set with pwmd_setopt(). The password may
1409 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1411 if (!pwm->passfunc && password && password != pwm->password)
1412 pwmd_free(password);
1414 if (rc == GPG_ERR_INV_PASSPHRASE) {
1415 if (++pwm->pin_try < pwm->pinentry_tries) {
1416 if (!get_custom_passphrase(pwm, NULL))
1417 goto done;
1419 #ifdef WITH_PINENTRY
1420 #ifdef WITH_TCP
1421 if (pwm->tcp_conn && !local_pinentry)
1422 return rc;
1423 else if (local_pinentry)
1424 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1425 else
1426 #else
1427 if (local_pinentry)
1428 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1429 else
1430 #endif
1431 #else
1432 #ifdef WITH_TCP
1433 if (pwm->tcp_conn)
1434 return rc;
1435 else
1436 #endif
1437 #endif
1438 rc = set_pinentry_retry(pwm);
1440 if (rc)
1441 return rc;
1443 goto gotpassword;
1445 #ifdef WITH_PINENTRY
1446 else if (local_pinentry)
1447 _pinentry_disconnect(pwm);
1448 #endif
1450 done:
1451 return rc;
1453 #ifdef WITH_PINENTRY
1454 else if (rc && local_pinentry)
1455 _pinentry_disconnect(pwm);
1456 #endif
1458 if (!rc) {
1459 if (pwm->filename)
1460 pwmd_free(pwm->filename);
1462 pwm->filename = pwmd_strdup(filename);
1465 return rc;
1468 gpg_error_t pwmd_open2(pwm_t *pwm, const char *filename)
1470 #ifndef WITH_PINENTRY
1471 return GPG_ERR_NOT_IMPLEMENTED;
1472 #else
1473 return do_pwmd_open(pwm, filename, 0, 1);
1474 #endif
1477 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
1479 return do_pwmd_open(pwm, filename, 0, 0);
1482 gpg_error_t pwmd_open_async2(pwm_t *pwm, const char *filename)
1484 #ifndef WITH_PINENTRY
1485 return GPG_ERR_NOT_IMPLEMENTED;
1486 #else
1487 if (!pwm || !filename)
1488 return GPG_ERR_INV_ARG;
1490 if (!pwm->ctx)
1491 return GPG_ERR_INV_STATE;
1493 if (pwm->cmd != ASYNC_CMD_NONE)
1494 return GPG_ERR_ASS_NESTED_COMMANDS;
1496 /* Initialize a new command since this is not a pinentry retry. */
1497 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1498 pwm->pin_try = 0;
1500 pwm->cmd = ASYNC_CMD_OPEN2;
1501 pwm->state = ASYNC_PROCESS;
1502 gpg_error_t rc = do_pwmd_open(pwm, filename, 1, 1);
1504 if (rc)
1505 reset_async(pwm, 0);
1507 return rc;
1508 #endif
1511 static gpg_error_t do_pwmd_save(pwm_t *pwm, int nb, int local_pinentry)
1513 char *result = NULL;
1514 char *password = NULL;
1515 gpg_error_t rc;
1517 if (!pwm)
1518 return GPG_ERR_INV_ARG;
1520 if (!pwm->ctx)
1521 return GPG_ERR_INV_STATE;
1523 rc = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1525 if (rc == GPG_ERR_ENOENT)
1526 rc = GPG_ERR_NOT_FOUND;
1528 if (rc && rc != GPG_ERR_NOT_FOUND)
1529 return rc;
1531 if (rc == GPG_ERR_NOT_FOUND) {
1532 rc = get_custom_passphrase(pwm, &password);
1534 if (rc && rc != GPG_ERR_NO_DATA)
1535 return rc;
1536 else if (rc == GPG_ERR_NO_DATA)
1537 rc = GPG_ERR_NOT_FOUND;
1538 else
1539 goto gotpassword;
1542 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1543 #ifdef WITH_PINENTRY
1544 /* Get the password using the LOCAL pinentry. */
1545 if (nb) {
1546 int p[2];
1547 pid_t pid;
1548 pwmd_nb_status_t pw;
1550 if (pipe(p) == -1)
1551 return gpg_error_from_syserror();
1553 #ifdef WITH_LIBPTH
1554 pid = pth_fork();
1555 #else
1556 pid = fork();
1557 #endif
1559 switch (pid) {
1560 case 0:
1561 close(p[0]);
1562 pw.fd = p[0];
1563 password = NULL;
1564 pw.error = _do_save_getpin(pwm, &password);
1566 if (!pw.error) {
1567 snprintf(pw.password, sizeof(pw.password), "%s",
1568 password);
1569 pwmd_free(password);
1571 #ifdef WITH_LIBPTH
1572 pth_write(p[1], &pw, sizeof(pw));
1573 #else
1574 write(p[1], &pw, sizeof(pw));
1575 #endif
1576 memset(&pw, 0, sizeof(pw));
1577 close(p[1]);
1578 _exit(0);
1579 break;
1580 case -1:
1581 rc = gpg_error_from_syserror();
1582 close(p[0]);
1583 close(p[1]);
1584 return rc;
1585 default:
1586 break;
1589 close(p[1]);
1590 pwm->nb_fd = p[0];
1591 pwm->nb_pid = pid;
1592 return 0;
1595 rc = _do_save_getpin(pwm, &password);
1597 if (rc)
1598 return rc;
1599 #endif
1601 else
1602 pwm->state = ASYNC_DONE;
1604 gotpassword:
1605 reset_async(pwm, 0);
1607 #ifdef WITH_TCP
1608 if (!local_pinentry && !pwm->tcp_conn) {
1609 #else
1610 if (!local_pinentry) {
1611 #endif
1612 rc = send_pinentry_options(pwm);
1614 if (rc)
1615 return rc;
1618 rc = pwmd_command(pwm, NULL, "SAVE %s", password ? password : "");
1620 if (!pwm->passfunc && password && password != pwm->password)
1621 pwmd_free(password);
1623 return rc;
1626 gpg_error_t pwmd_save_async2(pwm_t *pwm)
1628 #ifndef WITH_PINENTRY
1629 return GPG_ERR_NOT_IMPLEMENTED;
1630 #else
1631 if (!pwm)
1632 return GPG_ERR_INV_ARG;
1634 if (!pwm->ctx)
1635 return GPG_ERR_INV_STATE;
1637 if (pwm->cmd != ASYNC_CMD_NONE)
1638 return GPG_ERR_ASS_NESTED_COMMANDS;
1640 pwm->cmd = ASYNC_CMD_SAVE2;
1641 pwm->state = ASYNC_PROCESS;
1642 gpg_error_t rc = do_pwmd_save(pwm, 1, 1);
1644 if (rc)
1645 reset_async(pwm, 0);
1647 return rc;
1648 #endif
1651 gpg_error_t pwmd_save2(pwm_t *pwm)
1653 #ifndef WITH_PINENTRY
1654 return GPG_ERR_NOT_IMPLEMENTED;
1655 #else
1656 return do_pwmd_save(pwm, 0, 1);
1657 #endif
1660 gpg_error_t pwmd_save(pwm_t *pwm)
1662 return do_pwmd_save(pwm, 0, 0);
1665 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1667 va_list ap;
1668 int n = va_arg(ap, int);
1669 char *arg1;
1670 gpg_error_t rc = 0;
1672 if (!pwm)
1673 return GPG_ERR_INV_ARG;
1675 va_start(ap, opt);
1677 switch (opt) {
1678 case PWMD_OPTION_INQUIRE_TOTAL:
1679 n = va_arg(ap, size_t);
1680 pwm->inquire_total = n;
1681 break;
1682 case PWMD_OPTION_STATUS_CB:
1683 pwm->status_func = va_arg(ap, pwmd_status_cb_t);
1684 break;
1685 case PWMD_OPTION_STATUS_DATA:
1686 pwm->status_data = va_arg(ap, void *);
1687 break;
1688 case PWMD_OPTION_PASSPHRASE_CB:
1689 pwm->passfunc = va_arg(ap, pwmd_passphrase_cb_t);
1690 break;
1691 case PWMD_OPTION_PASSPHRASE_DATA:
1692 pwm->passdata = va_arg(ap, void *);
1693 break;
1694 case PWMD_OPTION_PASSPHRASE:
1695 arg1 = va_arg(ap, char *);
1697 if (pwm->password)
1698 pwmd_free(pwm->password);
1700 pwm->password = arg1 ? pwmd_strdup(arg1) : NULL;
1701 break;
1702 case PWMD_OPTION_PINENTRY_TRIES:
1703 n = va_arg(ap, int);
1705 if (n <= 0) {
1706 va_end(ap);
1707 rc = GPG_ERR_INV_VALUE;
1709 else
1710 pwm->pinentry_tries = n;
1711 break;
1712 case PWMD_OPTION_PINENTRY_TIMEOUT:
1713 n = va_arg(ap, int);
1715 if (n < 0) {
1716 va_end(ap);
1717 rc = GPG_ERR_INV_VALUE;
1719 else
1720 pwm->pinentry_timeout = n;
1721 break;
1722 case PWMD_OPTION_PINENTRY_PATH:
1723 if (pwm->pinentry_path)
1724 pwmd_free(pwm->pinentry_path);
1726 pwm->pinentry_path = _expand_homedir(va_arg(ap, char *), NULL);
1727 break;
1728 case PWMD_OPTION_PINENTRY_TTY:
1729 arg1 = va_arg(ap, char *);
1731 if (pwm->pinentry_tty)
1732 pwmd_free(pwm->pinentry_tty);
1734 pwm->pinentry_tty = arg1 ? pwmd_strdup(arg1) : NULL;
1735 break;
1736 case PWMD_OPTION_PINENTRY_DISPLAY:
1737 if (pwm->pinentry_display)
1738 pwmd_free(pwm->pinentry_display);
1740 pwm->pinentry_display = pwmd_strdup(va_arg(ap, char *));
1741 break;
1742 case PWMD_OPTION_PINENTRY_TERM:
1743 arg1 = va_arg(ap, char *);
1745 if (pwm->pinentry_term)
1746 pwmd_free(pwm->pinentry_term);
1748 pwm->pinentry_term = arg1 ? pwmd_strdup(arg1) : NULL;
1749 break;
1750 case PWMD_OPTION_PINENTRY_TITLE:
1751 if (pwm->title)
1752 pwmd_free(pwm->title);
1754 pwm->title = _percent_escape(va_arg(ap, char *));
1755 break;
1756 case PWMD_OPTION_PINENTRY_PROMPT:
1757 if (pwm->prompt)
1758 pwmd_free(pwm->prompt);
1760 pwm->prompt = _percent_escape(va_arg(ap, char *));
1761 break;
1762 case PWMD_OPTION_PINENTRY_DESC:
1763 if (pwm->desc)
1764 pwmd_free(pwm->desc);
1766 pwm->desc = _percent_escape(va_arg(ap, char *));
1767 break;
1768 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1769 arg1 = va_arg(ap, char *);
1771 if (pwm->lcctype)
1772 pwmd_free(pwm->lcctype);
1774 pwm->lcctype = arg1 ? pwmd_strdup(arg1) : NULL;
1775 break;
1776 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1777 arg1 = va_arg(ap, char *);
1779 if (pwm->lcmessages)
1780 pwmd_free(pwm->lcmessages);
1782 pwm->lcmessages = arg1 ? pwmd_strdup(arg1) : NULL;
1783 break;
1784 case PWMD_OPTION_IP_VERSION:
1785 #ifdef WITH_TCP
1786 n = va_arg(ap, int);
1788 switch (n) {
1789 case PWMD_IP_ANY:
1790 case PWMD_IPV4:
1791 case PWMD_IPV6:
1792 pwm->prot = n;
1793 break;
1794 default:
1795 rc = GPG_ERR_INV_VALUE;
1796 break;
1799 va_end(ap);
1800 #else
1801 rc = GPG_ERR_NOT_IMPLEMENTED;
1802 #endif
1803 break;
1804 case PWMD_OPTION_KNOWNHOST_CB:
1805 #ifdef WITH_TCP
1806 pwm->kh_cb = va_arg(ap, pwmd_knownhost_cb_t);
1807 #else
1808 rc = GPG_ERR_NOT_IMPLEMENTED;
1809 #endif
1810 break;
1811 case PWMD_OPTION_KNOWNHOST_DATA:
1812 #ifdef WITH_TCP
1813 pwm->kh_data = va_arg(ap, void *);
1814 #else
1815 rc = GPG_ERR_NOT_IMPLEMENTED;
1816 #endif
1817 break;
1818 default:
1819 rc = GPG_ERR_UNKNOWN_OPTION;
1820 break;
1823 va_end(ap);
1824 return rc;
1827 gpg_error_t pwmd_get_fds(pwm_t *pwm, pwmd_fd_t *fds, int *n_fds)
1829 int in_total;
1830 int fd = 0;
1831 #ifdef WITH_TCP
1832 int afds[ARES_GETSOCK_MAXNUM];
1833 int got_sock = 0;
1834 int n, i;
1835 #endif
1837 if (!pwm || !fds || !n_fds || *n_fds <= 0)
1838 return GPG_ERR_INV_ARG;
1840 in_total = *n_fds;
1841 #ifdef WITH_TCP
1842 memset(afds, 0, sizeof(int)*ARES_GETSOCK_MAXNUM);
1843 #endif
1844 memset(fds, 0, sizeof(pwmd_fd_t)*in_total);
1845 *n_fds = 0;
1847 switch (pwm->cmd) {
1848 default:
1849 case ASYNC_CMD_NONE:
1850 case ASYNC_CMD_OPEN:
1851 case ASYNC_CMD_SAVE:
1852 #ifdef WITH_PINENTRY
1853 async1:
1854 #endif
1855 if (pwm->fd == -1)
1856 return GPG_ERR_INV_STATE;
1858 (*n_fds)++;
1859 fds[fd].fd = pwm->fd;
1860 fds[fd++].flags = PWMD_FD_READABLE;
1861 return 0;
1862 #ifdef WITH_PINENTRY
1863 case ASYNC_CMD_OPEN2:
1864 case ASYNC_CMD_SAVE2:
1865 /* The command has already completed (cached or new). */
1866 if (pwm->state == ASYNC_DONE)
1867 return 0;
1869 if (pwm->nb_fd == -1)
1870 return GPG_ERR_INV_STATE;
1872 (*n_fds)++;
1873 fds[fd].fd = pwm->nb_fd;
1874 fds[fd++].flags = PWMD_FD_READABLE;
1875 goto async1;
1876 #endif
1877 #ifdef WITH_TCP
1878 case ASYNC_CMD_DNS:
1879 if (!pwm->tcp_conn || !pwm->tcp_conn->chan)
1880 return GPG_ERR_INV_STATE;
1882 n = ares_getsock(pwm->tcp_conn->chan, afds, ARES_GETSOCK_MAXNUM);
1884 for (i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
1885 got_sock = 0;
1887 if (fd > in_total) {
1888 *n_fds = fd;
1889 return GPG_ERR_ERANGE;
1892 if (ARES_GETSOCK_READABLE(n, i)) {
1893 got_sock++;
1894 fds[fd].flags |= PWMD_FD_READABLE;
1897 if (ARES_GETSOCK_WRITABLE(n, i)) {
1898 got_sock++;
1899 fds[fd].flags |= PWMD_FD_WRITABLE;
1902 if (got_sock)
1903 fds[fd++].fd = afds[i];
1906 *n_fds = fd;
1907 return 0;
1908 case ASYNC_CMD_CONNECT:
1909 case ASYNC_CMD_HOSTKEY:
1910 if (!pwm->tcp_conn || pwm->tcp_conn->fd == -1)
1911 return GPG_ERR_INV_STATE;
1913 (*n_fds)++;
1914 fds[fd].fd = pwm->tcp_conn->fd;
1915 fds[fd++].flags = PWMD_FD_READABLE;
1916 return 0;
1917 #endif
1920 return GPG_ERR_INV_STATE;
1923 pwm_t *pwmd_new(const char *name)
1925 pwm_t *h = pwmd_calloc(1, sizeof(pwm_t));
1927 if (!h)
1928 return NULL;
1930 if (name) {
1931 h->name = pwmd_strdup(name);
1933 if (!h->name) {
1934 pwmd_free(h);
1935 return NULL;
1939 reset_handle(h);
1940 h->pinentry_timeout = -30;
1941 h->pinentry_tries = 3;
1942 #ifdef WITH_TCP
1943 h->prot = PWMD_IP_ANY;
1944 #endif
1946 if (ttyname(STDOUT_FILENO)) {
1947 char buf[256];
1949 ttyname_r(STDOUT_FILENO, buf, sizeof(buf));
1950 h->pinentry_tty = pwmd_strdup(buf);
1952 if (!h->pinentry_tty)
1953 goto fail;
1956 if (getenv("TERM") && h->pinentry_tty) {
1957 h->pinentry_term = pwmd_strdup(getenv("TERM"));
1959 if (!h->pinentry_term)
1960 goto fail;
1963 if (getenv("DISPLAY")) {
1964 h->pinentry_display = pwmd_strdup(getenv("DISPLAY"));
1966 if (!h->pinentry_display)
1967 goto fail;
1970 return h;
1972 fail:
1973 pwmd_close(h);
1974 return NULL;
1977 void pwmd_free(void *ptr)
1979 _xfree(ptr);
1982 void *pwmd_malloc(size_t size)
1984 return _xmalloc(size);
1987 void *pwmd_calloc(size_t nmemb, size_t size)
1989 return _xcalloc(nmemb, size);
1992 void *pwmd_realloc(void *ptr, size_t size)
1994 return _xrealloc(ptr, size);
1997 char *pwmd_strdup(const char *str)
1999 return _xstrdup(str);
2002 char *pwmd_strdup_printf(const char *fmt, ...)
2004 va_list ap, ap2;
2005 int len;
2006 char *buf;
2008 if (!fmt)
2009 return NULL;
2011 va_start(ap, fmt);
2012 va_copy(ap2, ap);
2013 len = vsnprintf(NULL, 0, fmt, ap);
2014 va_end(ap);
2015 buf = pwmd_malloc(++len);
2017 if (buf)
2018 vsnprintf(buf, len, fmt, ap2);
2020 va_end(ap2);
2021 return buf;
2024 gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result,
2025 pwmd_pinentry_t which)
2027 #ifndef WITH_PINENTRY
2028 return GPG_ERR_NOT_IMPLEMENTED;
2029 #else
2030 return _pwmd_getpin(pwm, filename, result, which);
2031 #endif