Fixed EAGAIN when doing an SSH channel write.
[libpwmd.git] / src / libpwmd.c
blob3481e1e19c45c729b4234fccf059f190d7def35a
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 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <signal.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <sys/wait.h>
36 #include <fcntl.h>
37 #include <pwd.h>
38 #include <time.h>
39 #include <sys/types.h>
40 #include <limits.h>
41 #include <sys/select.h>
42 #include <libpwmd.h>
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)+1 > 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 if (pwm->tcp_conn)
148 pwm->tcp_conn->state = SSH_NONE;
149 #endif
151 if (pwm->name) {
152 rc = pwmd_command(pwm, NULL, "SET NAME=%s", pwm->name);
154 if (rc)
155 return rc;
158 return 0;
161 static gpg_error_t _pwmd_connect_url(pwm_t *pwm, const char *url, int async)
163 char *p = (char *)url;
164 gpg_error_t rc;
166 if (!pwm)
167 return GPG_ERR_INV_ARG;
169 if (!p || !strncmp(p, "file://", 7) || !strncmp(p, "local://", 8)) {
170 if (p) {
171 if (!strncmp(p, "file://", 7))
172 p += 7;
173 else
174 p += 8;
177 goto connect_uds;
179 else if (!strncmp(p, "ssh://", 6) || !strncmp(p, "ssh6://", 7) ||
180 !strncmp(p, "ssh4://", 7)) {
181 #ifndef WITH_TCP
182 return GPG_ERR_NOT_IMPLEMENTED;
183 #else
184 char *host = NULL;
185 int port = -1;
186 char *identity = NULL;
187 char *known_hosts = NULL;
188 char *username = NULL;
190 if (!strncmp(p, "ssh6://", 7)) {
191 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV6);
192 p += 7;
194 else if (!strncmp(p, "ssh4://", 7)) {
195 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV4);
196 p += 7;
198 else {
199 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IP_ANY);
200 p += 6;
203 if (rc)
204 return rc;
206 rc = _parse_ssh_url(p, &host, &port, &username, &identity,
207 &known_hosts);
209 if (rc)
210 goto fail;
212 if (async)
213 rc = pwmd_ssh_connect_async(pwm, host, port, identity, username,
214 known_hosts);
215 else
216 rc = pwmd_ssh_connect(pwm, host, port, identity, username,
217 known_hosts);
219 fail:
220 if (host)
221 pwmd_free(host);
223 if (username)
224 pwmd_free(username);
226 if (identity)
227 pwmd_free(identity);
229 if (known_hosts)
230 pwmd_free(known_hosts);
232 return rc;
233 #endif
236 connect_uds:
237 rc = pwmd_connect(pwm, p);
238 pwm->state = ASYNC_DONE;
239 return rc;
242 gpg_error_t pwmd_connect_url(pwm_t *pwm, const char *url)
244 return _pwmd_connect_url(pwm, url, 0);
247 gpg_error_t pwmd_connect_url_async(pwm_t *pwm, const char *url)
249 return _pwmd_connect_url(pwm, url, 1);
252 gpg_error_t pwmd_connect(pwm_t *pwm, const char *path)
254 char *socketpath = NULL;
255 assuan_context_t ctx;
256 struct passwd pw;
257 char *pwbuf;
258 gpg_error_t rc;
260 if (!pwm)
261 return GPG_ERR_INV_ARG;
263 pwbuf = _getpwuid(&pw);
265 if (!pwbuf)
266 return gpg_error_from_syserror();
268 if (!path || !*path)
269 socketpath = pwmd_strdup_printf("%s/.pwmd/socket", pw.pw_dir);
270 else
271 socketpath = _expand_homedir((char *)path, &pw);
273 pwmd_free(pwbuf);
275 if (!socketpath)
276 return GPG_ERR_ENOMEM;
278 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
279 pwmd_free(socketpath);
281 if (rc)
282 return gpg_err_code(rc);
284 pwm->ctx = ctx;
285 return _connect_finalize(pwm);
288 static void disconnect(pwm_t *pwm)
290 if (!pwm || !pwm->ctx)
291 return;
293 assuan_disconnect(pwm->ctx);
294 pwm->ctx = NULL;
295 pwm->fd = -1;
298 void pwmd_close(pwm_t *pwm)
300 if (!pwm)
301 return;
303 disconnect(pwm);
305 if (pwm->password)
306 pwmd_free(pwm->password);
308 if (pwm->title)
309 pwmd_free(pwm->title);
311 if (pwm->desc)
312 pwmd_free(pwm->desc);
314 if (pwm->prompt)
315 pwmd_free(pwm->prompt);
317 if (pwm->pinentry_tty)
318 pwmd_free(pwm->pinentry_tty);
320 if (pwm->pinentry_display)
321 pwmd_free(pwm->pinentry_display);
323 if (pwm->pinentry_term)
324 pwmd_free(pwm->pinentry_term);
326 if (pwm->lcctype)
327 pwmd_free(pwm->lcctype);
329 if (pwm->lcmessages)
330 pwmd_free(pwm->lcmessages);
332 if (pwm->filename)
333 pwmd_free(pwm->filename);
335 if (pwm->name)
336 pwmd_free(pwm->name);
338 if (pwm->cipher)
339 pwmd_free(pwm->cipher);
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 #ifdef WITH_TCP
355 static gpg_error_t do_async_command(pwm_t *pwm, char **result)
357 pwmd_async_t s;
358 gpg_error_t rc;
360 do {
361 s = pwmd_process(pwm, &rc, result);
363 if (s != ASYNC_DONE) {
364 #ifdef WITH_LIBPTH
365 pth_usleep(50000);
366 #else
367 usleep(50000);
368 #endif
370 } while (s != ASYNC_DONE);
372 return rc;
374 #endif
376 gpg_error_t pwmd_ssh_connect_async(pwm_t *pwm, const char *host, int port,
377 const char *identity, const char *user, const char *known_hosts)
379 #ifndef WITH_TCP
380 return GPG_ERR_NOT_IMPLEMENTED;
381 #else
382 return _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
383 known_hosts, ASYNC_CMD_CONNECT);
384 #endif
387 gpg_error_t pwmd_ssh_connect(pwm_t *pwm, const char *host, int port,
388 const char *identity, const char *user, const char *known_hosts)
390 #ifndef WITH_TCP
391 return GPG_ERR_NOT_IMPLEMENTED;
392 #else
393 gpg_error_t rc;
395 rc = _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
396 known_hosts, ASYNC_CMD_CONNECT);
397 return rc ? rc : do_async_command(pwm, NULL);
398 #endif
401 gpg_error_t pwmd_get_hostkey(pwm_t *pwm, const char *host, int port,
402 char **result)
404 #ifndef WITH_TCP
405 return GPG_ERR_NOT_IMPLEMENTED;
406 #else
407 gpg_error_t rc;
409 rc = _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
410 ASYNC_CMD_HOSTKEY);
412 return rc ? rc : do_async_command(pwm, result);
413 #endif
416 gpg_error_t pwmd_get_hostkey_async(pwm_t *pwm, const char *host, int port)
418 #ifndef WITH_TCP
419 return GPG_ERR_NOT_IMPLEMENTED;
420 #else
421 return _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
422 ASYNC_CMD_HOSTKEY);
423 #endif
426 static int inquire_realloc_cb(void *data, const void *buffer, size_t len)
428 membuf_t *mem = (membuf_t *)data;
429 void *p;
431 if (!buffer)
432 return 0;
434 if ((p = pwmd_realloc(mem->buf, mem->len + len)) == NULL)
435 return GPG_ERR_ENOMEM;
437 mem->buf = p;
438 memcpy((char *)mem->buf + mem->len, buffer, len);
439 mem->len += len;
440 return 0;
443 static int inquire_cb(void *data, const char *keyword)
445 pwm_t *pwm = (pwm_t *)data;
446 gpg_error_t rc = 0;
448 /* Shouldn't get this far without a callback. */
449 if (!pwm->inquire_func)
450 return GPG_ERR_INV_ARG;
452 for (;;) {
453 char *result = NULL;
454 size_t len;
455 gpg_error_t arc;
457 rc = pwm->inquire_func(pwm->inquire_data, keyword, rc, &result, &len);
458 rc = gpg_err_code(rc);
460 if (rc == GPG_ERR_EOF || !rc) {
461 if (len <= 0 && !result) {
462 rc = 0;
463 break;
465 else if ((len <= 0 && result) || (len && !result)) {
466 rc = GPG_ERR_INV_ARG;
467 break;
470 arc = assuan_send_data(pwm->ctx, result, len);
471 arc = gpg_err_code(arc);
473 if (rc == GPG_ERR_EOF) {
474 rc = arc;
475 break;
478 rc = arc;
480 else if (rc)
481 break;
483 if (!rc) {
484 pwm->inquire_sent += len;
486 if (pwm->status_func) {
487 char buf[ASSUAN_LINELENGTH];
489 snprintf(buf, sizeof(buf), "XFER %u %u", pwm->inquire_sent,
490 pwm->inquire_total);
491 rc = pwm->status_func(pwm->status_data, buf);
493 if (rc)
494 continue;
497 rc = _pwmd_process(pwm);
499 if (rc == GPG_ERR_EAGAIN)
500 rc = 0;
504 return gpg_err_code(rc);
507 static gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, ...)
509 char *buf;
510 gpg_error_t rc;
511 va_list ap;
512 int len;
514 if (pwm->state == ASYNC_DONE)
515 pwm->state = ASYNC_INIT;
517 if (pwm->state != ASYNC_INIT)
518 return GPG_ERR_INV_STATE;
520 buf = pwmd_malloc(ASSUAN_LINELENGTH+1);
522 if (!buf)
523 return GPG_ERR_ENOMEM;
525 va_start(ap, cmd);
526 len = vsnprintf(buf, ASSUAN_LINELENGTH+1, cmd, ap);
527 va_end(ap);
529 if (len >= ASSUAN_LINELENGTH+1) {
530 pwmd_free(buf);
531 return GPG_ERR_LINE_TOO_LONG;
534 rc = assuan_write_line(pwm->ctx, buf);
535 pwmd_free(buf);
537 if (!rc)
538 pwm->state = ASYNC_PROCESS;
540 return gpg_err_code(rc);
543 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
545 char *p = NULL;
546 const char *f = NULL;
547 gpg_error_t rc;
549 if (!pwm || !filename)
550 return GPG_ERR_INV_ARG;
552 if (!pwm->ctx)
553 return GPG_ERR_INV_STATE;
555 if (pwm->cmd != ASYNC_CMD_NONE)
556 return GPG_ERR_ASS_NESTED_COMMANDS;
558 if (pwm->lastcmd == ASYNC_CMD_NONE) {
559 pwm->pin_try = 0;
561 if (pwm->filename)
562 pwmd_free(pwm->filename);
564 pwm->filename = pwmd_strdup(filename);
566 if (!pwm->filename)
567 return GPG_ERR_ENOMEM;
569 gpg_error_t rc = send_pinentry_options(pwm);
571 if (rc)
572 return rc;
574 rc = get_custom_passphrase(pwm, &p);
576 if (rc && rc != GPG_ERR_NO_DATA)
577 return rc;
579 f = filename;
581 #ifdef WITH_PINENTRY
582 else if (pwm->lastcmd == ASYNC_CMD_OPEN2) {
583 p = pwm->_password;
584 f = pwm->filename;
586 #endif
587 else if (pwm->lastcmd == ASYNC_CMD_OPEN) {
588 rc = set_pinentry_retry(pwm);
590 if (rc)
591 return rc;
593 p = pwm->password;
594 f = filename;
596 else
597 return GPG_ERR_INV_STATE;
599 pwm->cmd = ASYNC_CMD_OPEN;
600 #ifdef WITH_TCP
601 return do_nb_command(pwm, "OPEN %s%s%s%s %s",
602 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
603 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
604 pwm->tcp_conn ? "--pinentry=0 " : "",
605 f, p ? p : "");
606 #else
607 return do_nb_command(pwm, "OPEN %s%s%s %s",
608 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
609 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
610 f, p ? p : "");
611 #endif
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;
645 char *tmp = pwmd_strdup_printf("%li", pwm->iterations);
646 #ifdef WITH_TCP
647 gpg_error_t rc = do_nb_command(pwm, "SAVE %s%s--iterations=%s --cipher=%s",
648 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
649 pwm->tcp_conn ? "--pinentry=0 " : "",
650 pwm->iterations != -1 ? tmp : "",
651 pwm->cipher ? pwm->cipher : "", p ? p : "");
652 #else
653 gpg_error_t rc = do_nb_command(pwm, "SAVE %s--iterations=%s --cipher=%s",
654 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
655 pwm->iterations != -1 ? tmp : "",
656 pwm->cipher ? pwm->cipher : "", p ? p : "");
657 #endif
659 pwmd_free(tmp);
660 return rc;
663 static gpg_error_t parse_assuan_line(pwm_t *pwm)
665 gpg_error_t rc;
666 char *line;
667 size_t len;
669 rc = assuan_read_line(pwm->ctx, &line, &len);
671 if (!rc) {
672 if (line[0] == 'O' && line[1] == 'K' &&
673 (line[2] == 0 || line[2] == ' ')) {
674 pwm->state = ASYNC_DONE;
676 else if (line[0] == '#') {
678 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
679 if (pwm->status_func) {
680 rc = pwm->status_func(pwm->status_data,
681 line[1] == 0 ? line+1 : line+2);
684 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
685 (line[3] == 0 || line[3] == ' ')) {
686 line += 4;
687 rc = atoi(line);
688 pwm->state = ASYNC_DONE;
692 return gpg_err_code(rc);
695 gpg_error_t pwmd_pending_line(pwm_t *pwm)
697 if (!pwm)
698 return GPG_ERR_INV_ARG;
700 if (!pwm->ctx)
701 return GPG_ERR_INV_STATE;
703 return assuan_pending_line(pwm->ctx) ? 0 : GPG_ERR_NO_DATA;
706 static pwmd_async_t reset_async(pwm_t *pwm, int done)
708 pwm->state = ASYNC_INIT;
709 pwm->cmd = pwm->lastcmd = ASYNC_CMD_NONE;
711 #ifdef WITH_PINENTRY
712 if (pwm->nb_fd != -1) {
713 close(pwm->nb_fd);
714 pwm->nb_fd = -1;
717 if (pwm->_password) {
718 pwmd_free(pwm->_password);
719 pwm->_password = NULL;
721 #endif
722 #ifdef WITH_TCP
723 if (pwm->tcp_conn)
724 pwm->tcp_conn->rc = 0;
726 if (done && pwm->tcp_conn) {
727 _free_ssh_conn(pwm->tcp_conn);
728 pwm->tcp_conn = NULL;
730 #endif
732 return ASYNC_DONE;
736 * Used for processing status messages when not in an async command and for
737 * waiting for the result from pwmd_open_async() and pwmd_save_async().
739 static gpg_error_t _pwmd_process(pwm_t *pwm)
741 gpg_error_t rc = 0;
742 fd_set fds;
743 struct timeval tv = {0, 0};
744 int n;
746 FD_ZERO(&fds);
747 FD_SET(pwm->fd, &fds);
748 #ifdef WITH_LIBPTH
749 n = pth_select(pwm->fd+1, &fds, NULL, NULL, &tv);
750 #else
751 n = select(pwm->fd+1, &fds, NULL, NULL, &tv);
752 #endif
754 if (n == -1)
755 return gpg_error_from_syserror();
757 if (n > 0) {
758 if (FD_ISSET(pwm->fd, &fds))
759 rc = parse_assuan_line(pwm);
762 while (!rc && assuan_pending_line(pwm->ctx))
763 rc = parse_assuan_line(pwm);
765 return gpg_err_code(rc);
768 static void reset_handle(pwm_t *h)
770 h->fd = -1;
771 #ifdef WITH_PINENTRY
772 if (h->pctx)
773 _pinentry_disconnect(h);
775 h->nb_fd = -1;
776 #endif
777 h->pin_try = 0;
778 reset_async(h, 0);
781 gpg_error_t pwmd_disconnect(pwm_t *pwm)
783 if (!pwm)
784 return GPG_ERR_INV_ARG;
786 #ifdef WITH_TCP
787 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
788 #else
789 if (pwm->fd == -1)
790 #endif
791 return GPG_ERR_INV_STATE;
793 if (pwm->fd != 1)
794 disconnect(pwm);
795 #ifdef WITH_TCP
796 else
797 _ssh_disconnect(pwm);
798 #endif
800 reset_handle(pwm);
801 return 0;
804 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc, char **result)
806 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
807 fd_set fds;
808 int n;
809 struct timeval tv = {0, 0};
810 #endif
812 if (result)
813 *result = NULL;
815 if (!rc)
816 return GPG_ERR_INV_ARG;
818 *rc = 0;
820 if (!pwm) {
821 *rc = GPG_ERR_INV_ARG;
822 return ASYNC_DONE;
824 else if (!pwm->ctx) {
825 switch (pwm->cmd) {
826 default:
827 *rc = GPG_ERR_INV_STATE;
828 return ASYNC_DONE;
829 #ifdef WITH_TCP
830 case ASYNC_CMD_DNS:
831 case ASYNC_CMD_CONNECT:
832 case ASYNC_CMD_HOSTKEY:
833 break;
834 #endif
838 /* When not in a command, this will let libassuan process status messages
839 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
840 * descriptor returned by pwmd_get_fd() to determine when this should be
841 * called or call pwmd_pending_line() to determine whether a buffered line
842 * needs to be processed. */
843 if (pwm->cmd == ASYNC_CMD_NONE) {
844 *rc = _pwmd_process(pwm);
845 return ASYNC_DONE;
848 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
849 if (pwm->state == ASYNC_DONE) {
850 *rc = _pwmd_process(pwm);
851 return reset_async(pwm, 0);
854 if (pwm->state != ASYNC_PROCESS) {
855 *rc = GPG_ERR_INV_STATE;
856 return ASYNC_DONE;
859 #ifdef WITH_TCP
860 if (pwm->cmd == ASYNC_CMD_DNS) {
861 fd_set rfds, wfds;
863 if (pwm->tcp_conn->rc) {
864 *rc = pwm->tcp_conn->rc;
865 return reset_async(pwm, 1);
868 FD_ZERO(&rfds);
869 FD_ZERO(&wfds);
870 n = ares_fds(pwm->tcp_conn->chan, &rfds, &wfds);
872 /* Shouldn't happen. */
873 if (!n)
874 return pwm->state;
876 #ifdef WITH_LIBPTH
877 n = pth_select(n, &rfds, &wfds, NULL, &tv);
878 #else
879 n = select(n, &rfds, &wfds, NULL, &tv);
880 #endif
882 if (n < 0) {
883 *rc = gpg_error_from_syserror();
884 return reset_async(pwm, 1);
887 if (n > 0)
888 ares_process(pwm->tcp_conn->chan, &rfds, &wfds);
890 return pwm->state;
892 else if (pwm->cmd == ASYNC_CMD_CONNECT) {
893 if (pwm->tcp_conn->rc == GPG_ERR_EINPROGRESS) {
894 int ret;
895 socklen_t len = sizeof(int);
897 FD_ZERO(&fds);
898 FD_SET(pwm->tcp_conn->fd, &fds);
899 #ifdef WITH_LIBPTH
900 n = pth_select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
901 #else
902 n = select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
903 #endif
905 if (!n || !FD_ISSET(pwm->tcp_conn->fd, &fds))
906 return pwm->state;
907 else if (n == -1) {
908 *rc = gpg_error_from_syserror();
909 return reset_async(pwm, 1);
912 ret = getsockopt(pwm->tcp_conn->fd, SOL_SOCKET, SO_ERROR, &n, &len);
914 if (ret || n) {
915 *rc = ret ? gpg_error_from_syserror() : gpg_error_from_errno(n);
916 return reset_async(pwm, 1);
919 pwm->tcp_conn->state = SSH_NONE;
920 pwm->tcp_conn->rc = 0;
921 *rc = _setup_ssh_session(pwm);
923 if (*rc && *rc != GPG_ERR_EAGAIN)
924 return reset_async(pwm, 1);
926 else if (pwm->tcp_conn->rc) {
927 *rc = pwm->tcp_conn->rc;
928 return reset_async(pwm, 1);
931 switch (pwm->tcp_conn->state) {
932 case SSH_INIT:
933 *rc = _setup_ssh_init(pwm);
934 break;
935 case SSH_AUTHLIST:
936 *rc = _setup_ssh_authlist(pwm);
937 break;
938 case SSH_AUTH:
939 *rc = _setup_ssh_auth(pwm);
940 break;
941 case SSH_AGENT:
942 *rc = _setup_ssh_agent(pwm);
943 break;
944 case SSH_CHANNEL:
945 *rc = _setup_ssh_channel(pwm);
946 break;
947 case SSH_SHELL:
948 *rc = _setup_ssh_shell(pwm);
949 break;
950 default:
951 break;
954 if (*rc == GPG_ERR_EAGAIN) {
955 *rc = 0;
956 return ASYNC_PROCESS;
959 if (!*rc) {
960 switch (pwm->tcp_conn->cmd) {
961 case ASYNC_CMD_HOSTKEY:
962 *result = pwmd_strdup(pwm->tcp_conn->hostkey);
964 if (!*result)
965 *rc = GPG_ERR_ENOMEM;
966 break;
967 default:
968 break;
972 return reset_async(pwm, *rc ? 1 : 0);
974 #endif
976 #ifdef WITH_PINENTRY
977 if (pwm->cmd == ASYNC_CMD_OPEN2 || pwm->cmd == ASYNC_CMD_SAVE2) {
978 int status;
980 if (pwm->nb_fd == -1) {
981 *rc = GPG_ERR_INV_STATE;
982 return reset_async(pwm, 0);
985 FD_ZERO(&fds);
986 FD_SET(pwm->nb_fd, &fds);
987 FD_SET(pwm->fd, &fds);
988 #ifdef WITH_LIBPTH
989 n = pth_select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
990 #else
991 n = select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
992 #endif
993 if (n < 0) {
994 *rc = gpg_error_from_syserror();
995 return reset_async(pwm, 0);
998 if (n > 0 && FD_ISSET(pwm->nb_fd, &fds)) {
999 pwmd_nb_status_t nb;
1000 #ifdef WITH_LIBPTH
1001 size_t len = pth_read(pwm->nb_fd, &nb, sizeof(nb));
1002 #else
1003 size_t len = read(pwm->nb_fd, &nb, sizeof(nb));
1004 #endif
1005 waitpid(pwm->nb_pid, &status, WNOHANG);
1007 if (len != sizeof(nb)) {
1008 memset(&nb, 0, sizeof(pwmd_nb_status_t));
1009 *rc = gpg_error_from_syserror();
1010 return reset_async(pwm, 0);
1013 *rc = nb.error;
1015 if (*rc)
1016 return reset_async(pwm, 0);
1018 /* Since the non-blocking pinentry returned a success, do a
1019 * non-blocking OPEN or SAVE. */
1020 pwmd_async_cmd_t c = pwm->cmd;
1021 reset_async(pwm, 0);
1022 pwm->_password = pwmd_strdup(nb.password);
1023 memset(&nb, 0, sizeof(pwmd_nb_status_t));
1024 pwm->lastcmd = c;
1026 if (!pwm->_password) {
1027 *rc = GPG_ERR_ENOMEM;
1028 return reset_async(pwm, 0);
1031 if (c == ASYNC_CMD_SAVE2)
1032 *rc = pwmd_save_async(pwm);
1033 else
1034 *rc = pwmd_open_async(pwm, pwm->filename);
1036 if (*rc) {
1037 reset_async(pwm, 0);
1038 return ASYNC_DONE;
1041 return ASYNC_PROCESS;
1044 /* Fall through so status messages can be processed during the
1045 * pinentry. */
1047 #endif
1049 if (pwm->fd < 0) {
1050 *rc = GPG_ERR_INV_STATE;
1051 return reset_async(pwm, 0);
1054 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
1055 * retries. */
1056 *rc = _pwmd_process(pwm);
1058 if (*rc && *rc != GPG_ERR_INV_PASSPHRASE)
1059 return reset_async(pwm, 0);
1061 if (pwm->cmd == ASYNC_CMD_OPEN &&
1062 *rc == GPG_ERR_INV_PASSPHRASE &&
1063 #ifdef WITH_TCP
1064 (!pwm->tcp_conn || (pwm->tcp_conn && pwm->lastcmd == ASYNC_CMD_OPEN2)) &&
1065 #endif
1066 ++pwm->pin_try < pwm->pinentry_tries) {
1067 if (!get_custom_passphrase(pwm, NULL))
1068 goto done;
1070 #ifdef WITH_PINENTRY
1071 if (pwm->_password) {
1072 reset_async(pwm, 0);
1073 pwm->lastcmd = ASYNC_CMD_OPEN2;
1074 *rc = pwmd_open_async2(pwm, pwm->filename);
1076 else {
1077 #endif
1078 reset_async(pwm, 0);
1079 pwm->lastcmd = ASYNC_CMD_OPEN;
1080 *rc = pwmd_open_async(pwm, pwm->filename);
1081 #ifdef WITH_PINENTRY
1083 #endif
1086 done:
1087 if (*rc || pwm->state == ASYNC_DONE)
1088 return reset_async(pwm, 0);
1090 return pwm->state;
1093 gpg_error_t _assuan_command(pwm_t *pwm, assuan_context_t ctx,
1094 char **result, const char *cmd)
1096 membuf_t data;
1097 gpg_error_t rc;
1099 if (!cmd || !*cmd)
1100 return GPG_ERR_INV_ARG;
1102 if (strlen(cmd) >= ASSUAN_LINELENGTH+1)
1103 return GPG_ERR_LINE_TOO_LONG;
1105 data.len = 0;
1106 data.buf = NULL;
1107 rc = assuan_transact(ctx, cmd, inquire_realloc_cb, &data,
1108 #ifdef WITH_QUALITY
1109 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1110 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1111 #else
1112 inquire_cb, pwm,
1113 #endif
1114 pwm->status_func, pwm->status_data);
1116 if (rc) {
1117 if (data.buf) {
1118 pwmd_free(data.buf);
1119 data.buf = NULL;
1122 else {
1123 if (data.buf) {
1124 inquire_realloc_cb(&data, "", 1);
1126 if (!result) {
1127 pwmd_free(data.buf);
1128 rc = GPG_ERR_INV_ARG;
1130 else
1131 *result = (char *)data.buf;
1135 return gpg_err_code(rc);
1138 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_cb_t fn,
1139 void *data)
1141 if (!pwm || !cmd || !fn)
1142 return GPG_ERR_INV_ARG;
1144 if (!pwm->ctx)
1145 return GPG_ERR_INV_STATE;
1147 pwm->inquire_func = fn;
1148 pwm->inquire_data = data;
1149 pwm->inquire_sent = 0;
1150 return _assuan_command(pwm, pwm->ctx, NULL, cmd);
1153 gpg_error_t pwmd_command_ap(pwm_t *pwm, char **result, const char *cmd,
1154 va_list ap)
1156 char *buf;
1157 size_t len;
1158 va_list ap2;
1160 if (!pwm || !cmd)
1161 return GPG_ERR_INV_ARG;
1163 if (!pwm->ctx)
1164 return GPG_ERR_INV_STATE;
1167 * C99 allows the dst pointer to be null which will calculate the length
1168 * of the would-be result and return it.
1170 va_copy(ap2, ap);
1171 len = vsnprintf(NULL, 0, cmd, ap)+1;
1172 buf = (char *)pwmd_malloc(len);
1174 if (!buf) {
1175 va_end(ap2);
1176 return GPG_ERR_ENOMEM;
1179 len = vsnprintf(buf, len, cmd, ap2);
1180 va_end(ap2);
1182 if (buf[strlen(buf)-1] == '\n')
1183 buf[strlen(buf)-1] = 0;
1185 if (buf[strlen(buf)-1] == '\r')
1186 buf[strlen(buf)-1] = 0;
1188 gpg_error_t rc = _assuan_command(pwm, pwm->ctx, result, buf);
1189 pwmd_free(buf);
1190 return rc;
1193 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
1195 va_list ap;
1197 if (!pwm || !cmd)
1198 return GPG_ERR_INV_ARG;
1200 if (!pwm->ctx)
1201 return GPG_ERR_INV_STATE;
1203 if (result)
1204 *result = NULL;
1206 va_start(ap, cmd);
1207 gpg_error_t rc = pwmd_command_ap(pwm, result, cmd, ap);
1208 va_end(ap);
1209 return rc;
1212 static gpg_error_t send_pinentry_options(pwm_t *pwm)
1214 gpg_error_t rc;
1216 if (pwm->pinentry_path) {
1217 rc = pwmd_command(pwm, NULL, "SET PINENTRY_PATH=%s",
1218 pwm->pinentry_path);
1220 if (rc)
1221 return rc;
1224 if (pwm->pinentry_tty) {
1225 rc = pwmd_command(pwm, NULL, "SET TTYNAME=%s", pwm->pinentry_tty);
1227 if (rc)
1228 return rc;
1231 if (pwm->pinentry_term) {
1232 rc = pwmd_command(pwm, NULL, "SET TTYTYPE=%s", pwm->pinentry_term);
1234 if (rc)
1235 return rc;
1238 if (pwm->pinentry_display) {
1239 rc = pwmd_command(pwm, NULL, "SET DISPLAY=%s",
1240 pwm->pinentry_display);
1242 if (rc)
1243 return rc;
1246 if (pwm->title) {
1247 rc = pwmd_command(pwm, NULL, "SET TITLE=%s", pwm->title);
1249 if (rc)
1250 return rc;
1253 if (pwm->desc) {
1254 rc = pwmd_command(pwm, NULL, "SET DESC=%s", pwm->desc);
1256 if (rc)
1257 return rc;
1260 if (pwm->prompt) {
1261 rc = pwmd_command(pwm, NULL, "SET PROMPT=%s", pwm->prompt);
1263 if (rc)
1264 return rc;
1267 if (pwm->lcctype) {
1268 rc = pwmd_command(pwm, NULL, "SET LC_CTYPE=%s", pwm->lcctype);
1270 if (rc)
1271 return rc;
1274 if (pwm->lcmessages) {
1275 rc = pwmd_command(pwm, NULL, "SET LC_MESSAGES=%s", pwm->lcmessages);
1277 if (rc)
1278 return rc;
1281 if (pwm->pinentry_timeout >= 0 && !pwm->pin_try) {
1282 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=%i",
1283 pwm->pinentry_timeout);
1285 if (rc)
1286 return rc;
1289 return 0;
1292 gpg_error_t pwmd_socket_type(pwm_t *pwm, pwmd_socket_t *result)
1294 if (!pwm || !result)
1295 return GPG_ERR_INV_ARG;
1297 #ifdef WITH_TCP
1298 if ((pwm->fd == -1 && !pwm->tcp_conn) ||
1299 (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1))
1300 #else
1301 if (pwm->fd == -1)
1302 #endif
1303 return GPG_ERR_INV_STATE;
1305 #ifdef WITH_TCP
1306 *result = pwm->tcp_conn ? PWMD_SOCKET_SSH : PWMD_SOCKET_LOCAL;
1307 #else
1308 *result = PWMD_SOCKET_LOCAL;
1309 #endif
1310 return 0;
1313 static gpg_error_t set_pinentry_retry(pwm_t *pwm)
1315 gpg_error_t rc = 0;
1317 if (pwm->pin_try == 1) {
1318 rc = pwmd_command(pwm, NULL, "SET TITLE=%s",
1319 N_("Invalid passphrase, please try again."));
1321 if (rc)
1322 return rc;
1324 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=0");
1327 return rc;
1330 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result)
1332 gpg_error_t rc = GPG_ERR_NO_DATA;
1334 if (result)
1335 *result = NULL;
1336 else {
1337 if (pwm->password || pwm->passfunc)
1338 return 0;
1341 if (pwm->password) {
1342 rc = 0;
1343 *result = pwm->password;
1345 else if (pwm->passfunc)
1346 rc = pwm->passfunc(pwm->passdata, result);
1348 return rc;
1351 static gpg_error_t do_pwmd_open(pwm_t *pwm, const char *filename, int nb,
1352 int local_pinentry)
1354 char *result = NULL;
1355 char *password = NULL;
1356 gpg_error_t rc;
1357 int no_pinentry = 0;
1359 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1360 pwm->pin_try = 0;
1362 if (!pwm || !filename || !*filename)
1363 return GPG_ERR_INV_ARG;
1365 if (!pwm->ctx)
1366 return GPG_ERR_INV_STATE;
1369 * Avoid calling pinentry if the password is cached on the server or if
1370 * this is a new file.
1372 rc = pwmd_command(pwm, &result, "ISCACHED %s", filename);
1374 if (rc == GPG_ERR_ENOENT)
1375 goto gotpassword;
1377 if (rc && rc != GPG_ERR_NOT_FOUND)
1378 return rc;
1380 if (rc == GPG_ERR_NOT_FOUND) {
1381 rc = get_custom_passphrase(pwm, &password);
1383 if (rc && rc != GPG_ERR_NO_DATA)
1384 return rc;
1385 else if (rc == GPG_ERR_NO_DATA)
1386 rc = GPG_ERR_NOT_FOUND;
1387 else
1388 goto gotpassword;
1391 #ifdef WITH_PINENTRY
1392 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1393 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1394 if (!pwm->pin_try)
1395 no_pinentry = 1;
1397 rc = _pinentry_open(pwm, filename, &password, nb);
1399 /* pwmd_process() should be called if using a non-blocking local
1400 * pinentry. */
1401 if (rc || (!rc && nb))
1402 return rc;
1404 #endif
1406 gotpassword:
1407 reset_async(pwm, 0);
1409 #ifdef WITH_TCP
1410 if (!local_pinentry && !pwm->tcp_conn && !pwm->pin_try) {
1411 #else
1412 if (!local_pinentry && !pwm->pin_try) {
1413 #endif
1414 rc = send_pinentry_options(pwm);
1416 if (rc)
1417 return rc;
1420 rc = pwmd_command(pwm, NULL, "OPEN %s%s%s%s %s",
1421 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1422 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1423 no_pinentry ? "--pinentry=0 " : "",
1424 filename, password ? password : "");
1427 * Keep the user defined password set with pwmd_setopt(). The password may
1428 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1430 if (!pwm->passfunc && password && password != pwm->password)
1431 pwmd_free(password);
1433 if (rc == GPG_ERR_INV_PASSPHRASE) {
1434 if (++pwm->pin_try < pwm->pinentry_tries) {
1435 if (!get_custom_passphrase(pwm, NULL))
1436 goto done;
1438 #ifdef WITH_PINENTRY
1439 #ifdef WITH_TCP
1440 if (pwm->tcp_conn && !local_pinentry)
1441 return rc;
1442 else if (local_pinentry)
1443 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1444 else
1445 #else
1446 if (local_pinentry)
1447 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1448 else
1449 #endif
1450 #else
1451 #ifdef WITH_TCP
1452 if (pwm->tcp_conn)
1453 return rc;
1454 else
1455 #endif
1456 #endif
1457 rc = set_pinentry_retry(pwm);
1459 if (rc)
1460 return rc;
1462 goto gotpassword;
1464 #ifdef WITH_PINENTRY
1465 else if (local_pinentry)
1466 _pinentry_disconnect(pwm);
1467 #endif
1469 done:
1470 return rc;
1472 #ifdef WITH_PINENTRY
1473 else if (rc && local_pinentry)
1474 _pinentry_disconnect(pwm);
1475 #endif
1477 if (!rc) {
1478 if (pwm->filename)
1479 pwmd_free(pwm->filename);
1481 pwm->filename = pwmd_strdup(filename);
1484 return rc;
1487 gpg_error_t pwmd_open2(pwm_t *pwm, const char *filename)
1489 #ifndef WITH_PINENTRY
1490 return GPG_ERR_NOT_IMPLEMENTED;
1491 #else
1492 return do_pwmd_open(pwm, filename, 0, 1);
1493 #endif
1496 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
1498 return do_pwmd_open(pwm, filename, 0, 0);
1501 gpg_error_t pwmd_open_async2(pwm_t *pwm, const char *filename)
1503 #ifndef WITH_PINENTRY
1504 return GPG_ERR_NOT_IMPLEMENTED;
1505 #else
1506 if (!pwm || !filename)
1507 return GPG_ERR_INV_ARG;
1509 if (!pwm->ctx)
1510 return GPG_ERR_INV_STATE;
1512 if (pwm->cmd != ASYNC_CMD_NONE)
1513 return GPG_ERR_ASS_NESTED_COMMANDS;
1515 /* Initialize a new command since this is not a pinentry retry. */
1516 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1517 pwm->pin_try = 0;
1519 pwm->cmd = ASYNC_CMD_OPEN2;
1520 pwm->state = ASYNC_PROCESS;
1521 gpg_error_t rc = do_pwmd_open(pwm, filename, 1, 1);
1523 if (rc)
1524 reset_async(pwm, 0);
1526 return rc;
1527 #endif
1530 struct open_inquire_s {
1531 pwm_t *pwm;
1532 char *filename;
1533 pwmd_inquire_cb_t func;
1534 void *user;
1535 int sent;
1538 /* We need to send the filename argument here rather than confusing the app.
1539 * The app will only send the passphrase and nothing else.
1541 static gpg_error_t open_inquire_cb(void *user, const char *cmd,
1542 gpg_error_t rc, char **data, size_t *len)
1544 struct open_inquire_s *o = user;
1546 if (rc)
1547 return rc;
1549 if (!o->sent) {
1550 char *line = pwmd_strdup_printf("%s ", o->filename);
1551 rc = assuan_send_data(o->pwm->ctx, line, strlen(line));
1553 pwmd_free(line);
1555 /* Give the user a chance to cleanup. */
1556 if (rc)
1557 return o->func(o->user, cmd, rc, data, len);
1559 o->sent = 1;
1562 return o->func(o->user, cmd, rc, data, len);
1565 gpg_error_t pwmd_open_inquire(pwm_t *pwm, const char *filename,
1566 pwmd_inquire_cb_t func, void *user)
1568 if (!pwm || !filename || !func)
1569 return GPG_ERR_INV_ARG;
1571 if (!pwm->ctx)
1572 return GPG_ERR_INV_STATE;
1574 struct open_inquire_s *inq = pwmd_calloc(1, sizeof(struct open_inquire_s));
1575 gpg_error_t rc;
1577 if (!inq)
1578 return GPG_ERR_ENOMEM;
1580 inq->pwm = pwm;
1581 inq->filename = pwmd_strdup(filename);
1582 inq->func = func;
1583 inq->user = user;
1585 char *cmd = pwmd_strdup_printf("OPEN --inquire %s%s",
1586 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1587 (pwm->opts & OPT_BASE64) ? "--base64 " : "");
1589 rc = pwmd_inquire(pwm, cmd, open_inquire_cb, inq);
1590 pwmd_free(cmd);
1591 pwmd_free(inq->filename);
1592 pwmd_free(inq);
1594 if (!rc) {
1595 if (pwm->filename)
1596 pwmd_free(pwm->filename);
1598 pwm->filename = pwmd_strdup(filename);
1600 if (!pwm->filename) {
1601 pwmd_close(pwm);
1602 rc = GPG_ERR_ENOMEM;
1606 return rc;
1609 gpg_error_t pwmd_save_inquire(pwm_t *pwm, pwmd_inquire_cb_t func, void *user)
1611 if (!pwm || !func)
1612 return GPG_ERR_INV_ARG;
1614 if (!pwm->ctx)
1615 return GPG_ERR_INV_STATE;
1617 gpg_error_t rc;
1618 char *tmp = pwmd_strdup_printf("%li", pwm->iterations);
1619 char *cmd = pwmd_strdup_printf("SAVE %s --inquire --iterations=%s --cipher=%s",
1620 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1621 pwm->iterations != -1 ? tmp : "",
1622 pwm->cipher ? pwm->cipher : "");
1624 rc = pwmd_inquire(pwm, cmd, func, user);
1625 pwmd_free(cmd);
1626 return rc;
1629 static gpg_error_t do_pwmd_save(pwm_t *pwm, int nb, int local_pinentry)
1631 char *result = NULL;
1632 char *password = NULL;
1633 gpg_error_t rc;
1635 if (!pwm)
1636 return GPG_ERR_INV_ARG;
1638 if (!pwm->ctx)
1639 return GPG_ERR_INV_STATE;
1641 rc = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1643 if (rc == GPG_ERR_ENOENT)
1644 rc = GPG_ERR_NOT_FOUND;
1646 if (rc && rc != GPG_ERR_NOT_FOUND)
1647 return rc;
1649 if (rc == GPG_ERR_NOT_FOUND) {
1650 rc = get_custom_passphrase(pwm, &password);
1652 if (rc && rc != GPG_ERR_NO_DATA)
1653 return rc;
1654 else if (rc == GPG_ERR_NO_DATA)
1655 rc = GPG_ERR_NOT_FOUND;
1656 else
1657 goto gotpassword;
1660 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1661 #ifdef WITH_PINENTRY
1662 /* Get the password using the LOCAL pinentry. */
1663 if (nb) {
1664 int p[2];
1665 pid_t pid;
1666 pwmd_nb_status_t pw;
1668 if (pipe(p) == -1)
1669 return gpg_error_from_syserror();
1671 #ifdef WITH_LIBPTH
1672 pid = pth_fork();
1673 #else
1674 pid = fork();
1675 #endif
1677 switch (pid) {
1678 case 0:
1679 close(p[0]);
1680 pw.fd = p[0];
1681 password = NULL;
1682 pw.error = _do_save_getpin(pwm, &password);
1684 if (!pw.error) {
1685 snprintf(pw.password, sizeof(pw.password), "%s",
1686 password);
1687 pwmd_free(password);
1689 #ifdef WITH_LIBPTH
1690 pth_write(p[1], &pw, sizeof(pw));
1691 #else
1692 write(p[1], &pw, sizeof(pw));
1693 #endif
1694 memset(&pw, 0, sizeof(pw));
1695 close(p[1]);
1696 _exit(0);
1697 break;
1698 case -1:
1699 rc = gpg_error_from_syserror();
1700 close(p[0]);
1701 close(p[1]);
1702 return rc;
1703 default:
1704 break;
1707 close(p[1]);
1708 pwm->nb_fd = p[0];
1709 pwm->nb_pid = pid;
1710 return 0;
1713 rc = _do_save_getpin(pwm, &password);
1715 if (rc)
1716 return rc;
1717 #endif
1719 else
1720 pwm->state = ASYNC_DONE;
1722 gotpassword:
1723 reset_async(pwm, 0);
1725 #ifdef WITH_TCP
1726 if (!local_pinentry && !pwm->tcp_conn) {
1727 #else
1728 if (!local_pinentry) {
1729 #endif
1730 rc = send_pinentry_options(pwm);
1732 if (rc)
1733 return rc;
1736 char *tmp = pwmd_strdup_printf("%li", pwm->iterations);
1738 #ifdef WITH_TCP
1739 rc = pwmd_command(pwm, NULL, "SAVE %s%s--iterations=%s --cipher=%s %s",
1740 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1741 local_pinentry || pwm->tcp_conn ? "--pinentry=0 " : "",
1742 pwm->iterations != -1 ? tmp : "",
1743 pwm->cipher ? pwm->cipher : "",
1744 password ? password : "");
1745 #else
1746 rc = pwmd_command(pwm, NULL, "SAVE %s--iterations=%s --cipher=%s %s",
1747 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1748 pwm->iterations != -1 ? tmp : "",
1749 pwm->cipher ? pwm->cipher : "",
1750 password ? password : "");
1751 #endif
1753 pwmd_free(tmp);
1755 if (!pwm->passfunc && password && password != pwm->password)
1756 pwmd_free(password);
1758 return rc;
1761 gpg_error_t pwmd_save_async2(pwm_t *pwm)
1763 #ifndef WITH_PINENTRY
1764 return GPG_ERR_NOT_IMPLEMENTED;
1765 #else
1766 if (!pwm)
1767 return GPG_ERR_INV_ARG;
1769 if (!pwm->ctx)
1770 return GPG_ERR_INV_STATE;
1772 if (pwm->cmd != ASYNC_CMD_NONE)
1773 return GPG_ERR_ASS_NESTED_COMMANDS;
1775 pwm->cmd = ASYNC_CMD_SAVE2;
1776 pwm->state = ASYNC_PROCESS;
1777 gpg_error_t rc = do_pwmd_save(pwm, 1, 1);
1779 if (rc)
1780 reset_async(pwm, 0);
1782 return rc;
1783 #endif
1786 gpg_error_t pwmd_save2(pwm_t *pwm)
1788 #ifndef WITH_PINENTRY
1789 return GPG_ERR_NOT_IMPLEMENTED;
1790 #else
1791 return do_pwmd_save(pwm, 0, 1);
1792 #endif
1795 gpg_error_t pwmd_save(pwm_t *pwm)
1797 return do_pwmd_save(pwm, 0, 0);
1800 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1802 va_list ap;
1803 int n;
1804 char *arg1;
1805 gpg_error_t rc = 0;
1807 if (!pwm)
1808 return GPG_ERR_INV_ARG;
1810 va_start(ap, opt);
1812 switch (opt) {
1813 case PWMD_OPTION_BASE64:
1814 n = va_arg(ap, int);
1816 if (n < 0 || n > 1) {
1817 rc = GPG_ERR_INV_VALUE;
1818 break;
1821 if (n)
1822 pwm->opts |= OPT_BASE64;
1823 else
1824 pwm->opts &= ~OPT_BASE64;
1826 break;
1827 case PWMD_OPTION_ITERATIONS:
1828 pwm->iterations = va_arg(ap, long);
1830 if (pwm->iterations < -1) {
1831 pwm->iterations = -1;
1832 rc = GPG_ERR_INV_VALUE;
1835 break;
1836 case PWMD_OPTION_CIPHER:
1837 arg1 = va_arg(ap, char *);
1839 if (pwm->cipher)
1840 pwmd_free(pwm->cipher);
1842 pwm->cipher = arg1 ? pwmd_strdup(arg1) : NULL;
1843 break;
1844 case PWMD_OPTION_LOCK_ON_OPEN:
1845 n = va_arg(ap, int);
1847 if (n < 0 || n > 1)
1848 rc = GPG_ERR_INV_VALUE;
1850 if (n)
1851 pwm->opts |= OPT_LOCK_ON_OPEN;
1852 else
1853 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1855 break;
1856 case PWMD_OPTION_INQUIRE_TOTAL:
1857 pwm->inquire_total = va_arg(ap, size_t);
1858 break;
1859 case PWMD_OPTION_STATUS_CB:
1860 pwm->status_func = va_arg(ap, pwmd_status_cb_t);
1861 break;
1862 case PWMD_OPTION_STATUS_DATA:
1863 pwm->status_data = va_arg(ap, void *);
1864 break;
1865 case PWMD_OPTION_PASSPHRASE_CB:
1866 pwm->passfunc = va_arg(ap, pwmd_passphrase_cb_t);
1867 break;
1868 case PWMD_OPTION_PASSPHRASE_DATA:
1869 pwm->passdata = va_arg(ap, void *);
1870 break;
1871 case PWMD_OPTION_PASSPHRASE:
1872 arg1 = va_arg(ap, char *);
1874 if (pwm->password)
1875 pwmd_free(pwm->password);
1877 pwm->password = arg1 ? pwmd_strdup(arg1) : NULL;
1878 break;
1879 case PWMD_OPTION_PINENTRY_TRIES:
1880 n = va_arg(ap, int);
1882 if (n <= 0)
1883 rc = GPG_ERR_INV_VALUE;
1884 else
1885 pwm->pinentry_tries = n;
1887 break;
1888 case PWMD_OPTION_PINENTRY_TIMEOUT:
1889 n = va_arg(ap, int);
1891 if (n < 0)
1892 rc = GPG_ERR_INV_VALUE;
1893 else
1894 pwm->pinentry_timeout = n;
1896 break;
1897 case PWMD_OPTION_PINENTRY_PATH:
1898 if (pwm->pinentry_path)
1899 pwmd_free(pwm->pinentry_path);
1901 pwm->pinentry_path = _expand_homedir(va_arg(ap, char *), NULL);
1902 break;
1903 case PWMD_OPTION_PINENTRY_TTY:
1904 arg1 = va_arg(ap, char *);
1906 if (pwm->pinentry_tty)
1907 pwmd_free(pwm->pinentry_tty);
1909 pwm->pinentry_tty = arg1 ? pwmd_strdup(arg1) : NULL;
1910 break;
1911 case PWMD_OPTION_PINENTRY_DISPLAY:
1912 if (pwm->pinentry_display)
1913 pwmd_free(pwm->pinentry_display);
1915 pwm->pinentry_display = pwmd_strdup(va_arg(ap, char *));
1916 break;
1917 case PWMD_OPTION_PINENTRY_TERM:
1918 arg1 = va_arg(ap, char *);
1920 if (pwm->pinentry_term)
1921 pwmd_free(pwm->pinentry_term);
1923 pwm->pinentry_term = arg1 ? pwmd_strdup(arg1) : NULL;
1924 break;
1925 case PWMD_OPTION_PINENTRY_TITLE:
1926 if (pwm->title)
1927 pwmd_free(pwm->title);
1929 pwm->title = _percent_escape(va_arg(ap, char *));
1930 break;
1931 case PWMD_OPTION_PINENTRY_PROMPT:
1932 if (pwm->prompt)
1933 pwmd_free(pwm->prompt);
1935 pwm->prompt = _percent_escape(va_arg(ap, char *));
1936 break;
1937 case PWMD_OPTION_PINENTRY_DESC:
1938 if (pwm->desc)
1939 pwmd_free(pwm->desc);
1941 pwm->desc = _percent_escape(va_arg(ap, char *));
1942 break;
1943 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1944 arg1 = va_arg(ap, char *);
1946 if (pwm->lcctype)
1947 pwmd_free(pwm->lcctype);
1949 pwm->lcctype = arg1 ? pwmd_strdup(arg1) : NULL;
1950 break;
1951 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1952 arg1 = va_arg(ap, char *);
1954 if (pwm->lcmessages)
1955 pwmd_free(pwm->lcmessages);
1957 pwm->lcmessages = arg1 ? pwmd_strdup(arg1) : NULL;
1958 break;
1959 #ifdef WITH_TCP
1960 case PWMD_OPTION_IP_VERSION:
1961 n = va_arg(ap, int);
1963 switch (n) {
1964 case PWMD_IP_ANY:
1965 case PWMD_IPV4:
1966 case PWMD_IPV6:
1967 pwm->prot = n;
1968 break;
1969 default:
1970 rc = GPG_ERR_INV_VALUE;
1971 break;
1973 break;
1974 case PWMD_OPTION_KNOWNHOST_CB:
1975 pwm->kh_cb = va_arg(ap, pwmd_knownhost_cb_t);
1976 break;
1977 case PWMD_OPTION_KNOWNHOST_DATA:
1978 pwm->kh_data = va_arg(ap, void *);
1979 break;
1980 case PWMD_OPTION_SSH_AGENT:
1981 pwm->use_agent = va_arg(ap, int);
1983 if (pwm->use_agent < 0 || pwm->use_agent > 1) {
1984 pwm->use_agent = 0;
1985 rc = GPG_ERR_INV_VALUE;
1988 break;
1989 #else
1990 case PWMD_OPTION_IP_VERSION:
1991 case PWMD_OPTION_KNOWNHOST_CB:
1992 case PWMD_OPTION_KNOWNHOST_DATA:
1993 case PWMD_OPTION_SSH_AGENT:
1994 rc = GPG_ERR_NOT_IMPLEMENTED;
1995 break;
1996 #endif
1997 default:
1998 rc = GPG_ERR_UNKNOWN_OPTION;
1999 break;
2002 va_end(ap);
2003 return rc;
2006 gpg_error_t pwmd_get_fds(pwm_t *pwm, pwmd_fd_t *fds, int *n_fds)
2008 int in_total;
2009 int fd = 0;
2010 #ifdef WITH_TCP
2011 int afds[ARES_GETSOCK_MAXNUM];
2012 int got_sock = 0;
2013 int n, i;
2014 #endif
2016 if (!pwm || !fds || !n_fds || *n_fds <= 0)
2017 return GPG_ERR_INV_ARG;
2019 in_total = *n_fds;
2020 #ifdef WITH_TCP
2021 memset(afds, 0, sizeof(int)*ARES_GETSOCK_MAXNUM);
2022 #endif
2023 memset(fds, 0, sizeof(pwmd_fd_t)*in_total);
2024 *n_fds = 0;
2026 switch (pwm->cmd) {
2027 default:
2028 case ASYNC_CMD_NONE:
2029 case ASYNC_CMD_OPEN:
2030 case ASYNC_CMD_SAVE:
2031 #ifdef WITH_PINENTRY
2032 async1:
2033 #endif
2034 if (pwm->fd == -1)
2035 return GPG_ERR_INV_STATE;
2037 (*n_fds)++;
2038 fds[fd].fd = pwm->fd;
2039 fds[fd++].flags = PWMD_FD_READABLE;
2040 return 0;
2041 #ifdef WITH_PINENTRY
2042 case ASYNC_CMD_OPEN2:
2043 case ASYNC_CMD_SAVE2:
2044 /* The command has already completed (cached or new). */
2045 if (pwm->state == ASYNC_DONE)
2046 return 0;
2048 if (pwm->nb_fd == -1)
2049 return GPG_ERR_INV_STATE;
2051 (*n_fds)++;
2052 fds[fd].fd = pwm->nb_fd;
2053 fds[fd++].flags = PWMD_FD_READABLE;
2054 goto async1;
2055 #endif
2056 #ifdef WITH_TCP
2057 case ASYNC_CMD_DNS:
2058 if (!pwm->tcp_conn || !pwm->tcp_conn->chan)
2059 return GPG_ERR_INV_STATE;
2061 n = ares_getsock(pwm->tcp_conn->chan, afds, ARES_GETSOCK_MAXNUM);
2063 for (i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
2064 got_sock = 0;
2066 if (fd > in_total) {
2067 *n_fds = fd;
2068 return GPG_ERR_ERANGE;
2071 if (ARES_GETSOCK_READABLE(n, i)) {
2072 got_sock++;
2073 fds[fd].flags |= PWMD_FD_READABLE;
2076 if (ARES_GETSOCK_WRITABLE(n, i)) {
2077 got_sock++;
2078 fds[fd].flags |= PWMD_FD_WRITABLE;
2081 if (got_sock)
2082 fds[fd++].fd = afds[i];
2085 *n_fds = fd;
2086 return 0;
2087 case ASYNC_CMD_CONNECT:
2088 case ASYNC_CMD_HOSTKEY:
2089 if (!pwm->tcp_conn || pwm->tcp_conn->fd == -1)
2090 return GPG_ERR_INV_STATE;
2092 (*n_fds)++;
2093 fds[fd].fd = pwm->tcp_conn->fd;
2094 fds[fd++].flags = PWMD_FD_READABLE;
2095 return 0;
2096 #endif
2099 return GPG_ERR_INV_STATE;
2102 pwm_t *pwmd_new(const char *name)
2104 pwm_t *h = pwmd_calloc(1, sizeof(pwm_t));
2106 if (!h)
2107 return NULL;
2109 if (name) {
2110 h->name = pwmd_strdup(name);
2112 if (!h->name) {
2113 pwmd_free(h);
2114 return NULL;
2118 reset_handle(h);
2119 h->pinentry_timeout = -30;
2120 h->pinentry_tries = 3;
2121 h->iterations = -1;
2122 #ifdef WITH_TCP
2123 h->prot = PWMD_IP_ANY;
2124 #endif
2126 if (ttyname(STDOUT_FILENO)) {
2127 char buf[256];
2129 ttyname_r(STDOUT_FILENO, buf, sizeof(buf));
2130 h->pinentry_tty = pwmd_strdup(buf);
2132 if (!h->pinentry_tty)
2133 goto fail;
2136 if (getenv("TERM") && h->pinentry_tty) {
2137 h->pinentry_term = pwmd_strdup(getenv("TERM"));
2139 if (!h->pinentry_term)
2140 goto fail;
2143 if (getenv("DISPLAY")) {
2144 h->pinentry_display = pwmd_strdup(getenv("DISPLAY"));
2146 if (!h->pinentry_display)
2147 goto fail;
2150 return h;
2152 fail:
2153 pwmd_close(h);
2154 return NULL;
2157 void pwmd_free(void *ptr)
2159 _xfree(ptr);
2162 void *pwmd_malloc(size_t size)
2164 return _xmalloc(size);
2167 void *pwmd_calloc(size_t nmemb, size_t size)
2169 return _xcalloc(nmemb, size);
2172 void *pwmd_realloc(void *ptr, size_t size)
2174 return _xrealloc(ptr, size);
2177 char *pwmd_strdup(const char *str)
2179 return _xstrdup(str);
2182 char *pwmd_strdup_printf(const char *fmt, ...)
2184 va_list ap, ap2;
2185 int len;
2186 char *buf;
2188 if (!fmt)
2189 return NULL;
2191 va_start(ap, fmt);
2192 va_copy(ap2, ap);
2193 len = vsnprintf(NULL, 0, fmt, ap);
2194 va_end(ap);
2195 buf = pwmd_malloc(++len);
2197 if (buf)
2198 vsnprintf(buf, len, fmt, ap2);
2200 va_end(ap2);
2201 return buf;
2204 gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result,
2205 pwmd_pinentry_t which)
2207 #ifndef WITH_PINENTRY
2208 return GPG_ERR_NOT_IMPLEMENTED;
2209 #else
2210 return _pwmd_getpin(pwm, filename, result, which);
2211 #endif
2214 const char *pwmd_version()
2216 return LIBPWMD_VERSION_STR;