Added ssh-agent support. Enable with PWMD_OPTION_SSH_AGENT.
[libpwmd.git] / src / libpwmd.c
blob5aaa23e656f5660b2e7053b91e7ec5d539773eb6
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;
447 int is_eagain = 0;
449 /* Shouldn't get this far without a callback. */
450 if (!pwm->inquire_func)
451 return GPG_ERR_INV_ARG;
453 for (;;) {
454 char *result = NULL;
455 size_t len;
456 gpg_error_t arc;
458 rc = pwm->inquire_func(pwm->inquire_data, keyword, rc, &result, &len);
459 rc = gpg_err_code(rc);
461 if (rc == GPG_ERR_EOF || !rc) {
462 if (len <= 0 && !result) {
463 rc = 0;
464 break;
466 else if ((len <= 0 && result) || (len && !result)) {
467 rc = GPG_ERR_INV_ARG;
468 break;
471 eagain:
472 is_eagain = 0;
473 arc = assuan_send_data(pwm->ctx, result, len);
474 arc = gpg_err_code(arc);
476 if (rc == GPG_ERR_EOF) {
477 rc = arc;
478 break;
481 rc = arc;
483 if (rc == GPG_ERR_EAGAIN) {
484 rc = 0;
485 is_eagain = 1;
486 goto process;
489 else if (rc)
490 break;
492 if (!rc) {
493 pwm->inquire_sent += len;
495 if (pwm->status_func) {
496 char buf[ASSUAN_LINELENGTH];
498 snprintf(buf, sizeof(buf), "XFER %u %u", pwm->inquire_sent,
499 pwm->inquire_total);
500 rc = pwm->status_func(pwm->status_data, buf);
502 if (rc)
503 continue;
506 process:
507 rc = _pwmd_process(pwm);
509 if (rc == GPG_ERR_EAGAIN)
510 rc = 0;
513 if (!rc && is_eagain) {
514 #ifdef WITH_LIBPTH
515 pth_usleep(100000);
516 #else
517 usleep(100000);
518 #endif
519 goto eagain;
523 return gpg_err_code(rc);
526 static gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, ...)
528 char *buf;
529 gpg_error_t rc;
530 va_list ap;
531 int len;
533 if (pwm->state == ASYNC_DONE)
534 pwm->state = ASYNC_INIT;
536 if (pwm->state != ASYNC_INIT)
537 return GPG_ERR_INV_STATE;
539 buf = pwmd_malloc(ASSUAN_LINELENGTH+1);
541 if (!buf)
542 return GPG_ERR_ENOMEM;
544 va_start(ap, cmd);
545 len = vsnprintf(buf, ASSUAN_LINELENGTH+1, cmd, ap);
546 va_end(ap);
548 if (len >= ASSUAN_LINELENGTH+1) {
549 pwmd_free(buf);
550 return GPG_ERR_LINE_TOO_LONG;
553 rc = assuan_write_line(pwm->ctx, buf);
554 pwmd_free(buf);
556 if (!rc)
557 pwm->state = ASYNC_PROCESS;
559 return gpg_err_code(rc);
562 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
564 char *p = NULL;
565 const char *f = NULL;
566 gpg_error_t rc;
568 if (!pwm || !filename)
569 return GPG_ERR_INV_ARG;
571 if (!pwm->ctx)
572 return GPG_ERR_INV_STATE;
574 if (pwm->cmd != ASYNC_CMD_NONE)
575 return GPG_ERR_ASS_NESTED_COMMANDS;
577 if (pwm->lastcmd == ASYNC_CMD_NONE) {
578 pwm->pin_try = 0;
580 if (pwm->filename)
581 pwmd_free(pwm->filename);
583 pwm->filename = pwmd_strdup(filename);
585 if (!pwm->filename)
586 return GPG_ERR_ENOMEM;
588 gpg_error_t rc = send_pinentry_options(pwm);
590 if (rc)
591 return rc;
593 rc = get_custom_passphrase(pwm, &p);
595 if (rc && rc != GPG_ERR_NO_DATA)
596 return rc;
598 f = filename;
600 #ifdef WITH_PINENTRY
601 else if (pwm->lastcmd == ASYNC_CMD_OPEN2) {
602 p = pwm->_password;
603 f = pwm->filename;
605 #endif
606 else if (pwm->lastcmd == ASYNC_CMD_OPEN) {
607 rc = set_pinentry_retry(pwm);
609 if (rc)
610 return rc;
612 p = pwm->password;
613 f = filename;
615 else
616 return GPG_ERR_INV_STATE;
618 pwm->cmd = ASYNC_CMD_OPEN;
619 #ifdef WITH_TCP
620 return do_nb_command(pwm, "OPEN %s%s%s%s %s",
621 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
622 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
623 pwm->tcp_conn ? "--pinentry=0 " : "",
624 f, p ? p : "");
625 #else
626 return do_nb_command(pwm, "OPEN %s%s%s %s",
627 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
628 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
629 f, p ? p : "");
630 #endif
633 gpg_error_t pwmd_save_async(pwm_t *pwm)
635 char *p = NULL;
637 if (!pwm)
638 return GPG_ERR_INV_ARG;
640 if (!pwm->ctx)
641 return GPG_ERR_INV_STATE;
643 if (pwm->cmd != ASYNC_CMD_NONE)
644 return GPG_ERR_ASS_NESTED_COMMANDS;
646 if (pwm->lastcmd != ASYNC_CMD_SAVE2) {
647 gpg_error_t rc = send_pinentry_options(pwm);
649 if (rc)
650 return rc;
652 rc = get_custom_passphrase(pwm, &p);
654 if (rc && rc != GPG_ERR_NO_DATA)
655 return rc;
657 #ifdef WITH_PINENTRY
658 else
659 p = pwm->_password;
660 #endif
662 pwm->cmd = ASYNC_CMD_SAVE;
664 char *tmp = pwmd_strdup_printf("%li", pwm->iterations);
665 #ifdef WITH_TCP
666 gpg_error_t rc = do_nb_command(pwm, "SAVE %s%s--iterations=%s --cipher=%s",
667 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
668 pwm->tcp_conn ? "--pinentry=0 " : "",
669 pwm->iterations != -1 ? tmp : "",
670 pwm->cipher ? pwm->cipher : "", p ? p : "");
671 #else
672 gpg_error_t rc = do_nb_command(pwm, "SAVE %s--iterations=%s --cipher=%s",
673 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
674 pwm->iterations != -1 ? tmp : "",
675 pwm->cipher ? pwm->cipher : "", p ? p : "");
676 #endif
678 pwmd_free(tmp);
679 return rc;
682 static gpg_error_t parse_assuan_line(pwm_t *pwm)
684 gpg_error_t rc;
685 char *line;
686 size_t len;
688 rc = assuan_read_line(pwm->ctx, &line, &len);
690 if (!rc) {
691 if (line[0] == 'O' && line[1] == 'K' &&
692 (line[2] == 0 || line[2] == ' ')) {
693 pwm->state = ASYNC_DONE;
695 else if (line[0] == '#') {
697 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
698 if (pwm->status_func) {
699 rc = pwm->status_func(pwm->status_data,
700 line[1] == 0 ? line+1 : line+2);
703 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
704 (line[3] == 0 || line[3] == ' ')) {
705 line += 4;
706 rc = atoi(line);
707 pwm->state = ASYNC_DONE;
711 return gpg_err_code(rc);
714 gpg_error_t pwmd_pending_line(pwm_t *pwm)
716 if (!pwm)
717 return GPG_ERR_INV_ARG;
719 if (!pwm->ctx)
720 return GPG_ERR_INV_STATE;
722 return assuan_pending_line(pwm->ctx) ? 0 : GPG_ERR_NO_DATA;
725 static pwmd_async_t reset_async(pwm_t *pwm, int done)
727 pwm->state = ASYNC_INIT;
728 pwm->cmd = pwm->lastcmd = ASYNC_CMD_NONE;
730 #ifdef WITH_PINENTRY
731 if (pwm->nb_fd != -1) {
732 close(pwm->nb_fd);
733 pwm->nb_fd = -1;
736 if (pwm->_password) {
737 pwmd_free(pwm->_password);
738 pwm->_password = NULL;
740 #endif
741 #ifdef WITH_TCP
742 if (pwm->tcp_conn)
743 pwm->tcp_conn->rc = 0;
745 if (done && pwm->tcp_conn) {
746 _free_ssh_conn(pwm->tcp_conn);
747 pwm->tcp_conn = NULL;
749 #endif
751 return ASYNC_DONE;
755 * Used for processing status messages when not in an async command and for
756 * waiting for the result from pwmd_open_async() and pwmd_save_async().
758 static gpg_error_t _pwmd_process(pwm_t *pwm)
760 gpg_error_t rc = 0;
761 fd_set fds;
762 struct timeval tv = {0, 0};
763 int n;
765 FD_ZERO(&fds);
766 FD_SET(pwm->fd, &fds);
767 #ifdef WITH_LIBPTH
768 n = pth_select(pwm->fd+1, &fds, NULL, NULL, &tv);
769 #else
770 n = select(pwm->fd+1, &fds, NULL, NULL, &tv);
771 #endif
773 if (n == -1)
774 return gpg_error_from_syserror();
776 if (n > 0) {
777 if (FD_ISSET(pwm->fd, &fds))
778 rc = parse_assuan_line(pwm);
781 while (!rc && assuan_pending_line(pwm->ctx))
782 rc = parse_assuan_line(pwm);
784 return gpg_err_code(rc);
787 static void reset_handle(pwm_t *h)
789 h->fd = -1;
790 #ifdef WITH_PINENTRY
791 if (h->pctx)
792 _pinentry_disconnect(h);
794 h->nb_fd = -1;
795 #endif
796 h->pin_try = 0;
797 reset_async(h, 0);
800 gpg_error_t pwmd_disconnect(pwm_t *pwm)
802 if (!pwm)
803 return GPG_ERR_INV_ARG;
805 #ifdef WITH_TCP
806 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
807 #else
808 if (pwm->fd == -1)
809 #endif
810 return GPG_ERR_INV_STATE;
812 if (pwm->fd != 1)
813 disconnect(pwm);
814 #ifdef WITH_TCP
815 else
816 _ssh_disconnect(pwm);
817 #endif
819 reset_handle(pwm);
820 return 0;
823 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc, char **result)
825 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
826 fd_set fds;
827 int n;
828 struct timeval tv = {0, 0};
829 #endif
831 if (result)
832 *result = NULL;
834 if (!rc)
835 return GPG_ERR_INV_ARG;
837 *rc = 0;
839 if (!pwm) {
840 *rc = GPG_ERR_INV_ARG;
841 return ASYNC_DONE;
843 else if (!pwm->ctx) {
844 switch (pwm->cmd) {
845 default:
846 *rc = GPG_ERR_INV_STATE;
847 return ASYNC_DONE;
848 #ifdef WITH_TCP
849 case ASYNC_CMD_DNS:
850 case ASYNC_CMD_CONNECT:
851 case ASYNC_CMD_HOSTKEY:
852 break;
853 #endif
857 /* When not in a command, this will let libassuan process status messages
858 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
859 * descriptor returned by pwmd_get_fd() to determine when this should be
860 * called or call pwmd_pending_line() to determine whether a buffered line
861 * needs to be processed. */
862 if (pwm->cmd == ASYNC_CMD_NONE) {
863 *rc = _pwmd_process(pwm);
864 return ASYNC_DONE;
867 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
868 if (pwm->state == ASYNC_DONE) {
869 *rc = _pwmd_process(pwm);
870 return reset_async(pwm, 0);
873 if (pwm->state != ASYNC_PROCESS) {
874 *rc = GPG_ERR_INV_STATE;
875 return ASYNC_DONE;
878 #ifdef WITH_TCP
879 if (pwm->cmd == ASYNC_CMD_DNS) {
880 fd_set rfds, wfds;
882 if (pwm->tcp_conn->rc) {
883 *rc = pwm->tcp_conn->rc;
884 return reset_async(pwm, 1);
887 FD_ZERO(&rfds);
888 FD_ZERO(&wfds);
889 n = ares_fds(pwm->tcp_conn->chan, &rfds, &wfds);
891 /* Shouldn't happen. */
892 if (!n)
893 return pwm->state;
895 #ifdef WITH_LIBPTH
896 n = pth_select(n, &rfds, &wfds, NULL, &tv);
897 #else
898 n = select(n, &rfds, &wfds, NULL, &tv);
899 #endif
901 if (n < 0) {
902 *rc = gpg_error_from_syserror();
903 return reset_async(pwm, 1);
906 if (n > 0)
907 ares_process(pwm->tcp_conn->chan, &rfds, &wfds);
909 return pwm->state;
911 else if (pwm->cmd == ASYNC_CMD_CONNECT) {
912 if (pwm->tcp_conn->rc == GPG_ERR_EINPROGRESS) {
913 int ret;
914 socklen_t len = sizeof(int);
916 FD_ZERO(&fds);
917 FD_SET(pwm->tcp_conn->fd, &fds);
918 #ifdef WITH_LIBPTH
919 n = pth_select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
920 #else
921 n = select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
922 #endif
924 if (!n || !FD_ISSET(pwm->tcp_conn->fd, &fds))
925 return pwm->state;
926 else if (n == -1) {
927 *rc = gpg_error_from_syserror();
928 return reset_async(pwm, 1);
931 ret = getsockopt(pwm->tcp_conn->fd, SOL_SOCKET, SO_ERROR, &n, &len);
933 if (ret || n) {
934 *rc = ret ? gpg_error_from_syserror() : gpg_error_from_errno(n);
935 return reset_async(pwm, 1);
938 pwm->tcp_conn->state = SSH_NONE;
939 pwm->tcp_conn->rc = 0;
940 *rc = _setup_ssh_session(pwm);
942 if (*rc && *rc != GPG_ERR_EAGAIN)
943 return reset_async(pwm, 1);
945 else if (pwm->tcp_conn->rc) {
946 *rc = pwm->tcp_conn->rc;
947 return reset_async(pwm, 1);
950 switch (pwm->tcp_conn->state) {
951 case SSH_INIT:
952 *rc = _setup_ssh_init(pwm);
953 break;
954 case SSH_AUTHLIST:
955 *rc = _setup_ssh_authlist(pwm);
956 break;
957 case SSH_AUTH:
958 *rc = _setup_ssh_auth(pwm);
959 break;
960 case SSH_AGENT:
961 *rc = _setup_ssh_agent(pwm);
962 break;
963 case SSH_CHANNEL:
964 *rc = _setup_ssh_channel(pwm);
965 break;
966 case SSH_SHELL:
967 *rc = _setup_ssh_shell(pwm);
968 break;
969 default:
970 break;
973 if (*rc == GPG_ERR_EAGAIN) {
974 *rc = 0;
975 return ASYNC_PROCESS;
978 if (!*rc) {
979 switch (pwm->tcp_conn->cmd) {
980 case ASYNC_CMD_HOSTKEY:
981 *result = pwmd_strdup(pwm->tcp_conn->hostkey);
983 if (!*result)
984 *rc = GPG_ERR_ENOMEM;
985 break;
986 default:
987 break;
991 return reset_async(pwm, *rc ? 1 : 0);
993 #endif
995 #ifdef WITH_PINENTRY
996 if (pwm->cmd == ASYNC_CMD_OPEN2 || pwm->cmd == ASYNC_CMD_SAVE2) {
997 int status;
999 if (pwm->nb_fd == -1) {
1000 *rc = GPG_ERR_INV_STATE;
1001 return reset_async(pwm, 0);
1004 FD_ZERO(&fds);
1005 FD_SET(pwm->nb_fd, &fds);
1006 FD_SET(pwm->fd, &fds);
1007 #ifdef WITH_LIBPTH
1008 n = pth_select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
1009 #else
1010 n = select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
1011 #endif
1012 if (n < 0) {
1013 *rc = gpg_error_from_syserror();
1014 return reset_async(pwm, 0);
1017 if (n > 0 && FD_ISSET(pwm->nb_fd, &fds)) {
1018 pwmd_nb_status_t nb;
1019 #ifdef WITH_LIBPTH
1020 size_t len = pth_read(pwm->nb_fd, &nb, sizeof(nb));
1021 #else
1022 size_t len = read(pwm->nb_fd, &nb, sizeof(nb));
1023 #endif
1024 waitpid(pwm->nb_pid, &status, WNOHANG);
1026 if (len != sizeof(nb)) {
1027 memset(&nb, 0, sizeof(pwmd_nb_status_t));
1028 *rc = gpg_error_from_syserror();
1029 return reset_async(pwm, 0);
1032 *rc = nb.error;
1034 if (*rc)
1035 return reset_async(pwm, 0);
1037 /* Since the non-blocking pinentry returned a success, do a
1038 * non-blocking OPEN or SAVE. */
1039 pwmd_async_cmd_t c = pwm->cmd;
1040 reset_async(pwm, 0);
1041 pwm->_password = pwmd_strdup(nb.password);
1042 memset(&nb, 0, sizeof(pwmd_nb_status_t));
1043 pwm->lastcmd = c;
1045 if (!pwm->_password) {
1046 *rc = GPG_ERR_ENOMEM;
1047 return reset_async(pwm, 0);
1050 if (c == ASYNC_CMD_SAVE2)
1051 *rc = pwmd_save_async(pwm);
1052 else
1053 *rc = pwmd_open_async(pwm, pwm->filename);
1055 if (*rc) {
1056 reset_async(pwm, 0);
1057 return ASYNC_DONE;
1060 return ASYNC_PROCESS;
1063 /* Fall through so status messages can be processed during the
1064 * pinentry. */
1066 #endif
1068 if (pwm->fd < 0) {
1069 *rc = GPG_ERR_INV_STATE;
1070 return reset_async(pwm, 0);
1073 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
1074 * retries. */
1075 *rc = _pwmd_process(pwm);
1077 if (*rc && *rc != GPG_ERR_INV_PASSPHRASE)
1078 return reset_async(pwm, 0);
1080 if (pwm->cmd == ASYNC_CMD_OPEN &&
1081 *rc == GPG_ERR_INV_PASSPHRASE &&
1082 #ifdef WITH_TCP
1083 (!pwm->tcp_conn || (pwm->tcp_conn && pwm->lastcmd == ASYNC_CMD_OPEN2)) &&
1084 #endif
1085 ++pwm->pin_try < pwm->pinentry_tries) {
1086 if (!get_custom_passphrase(pwm, NULL))
1087 goto done;
1089 #ifdef WITH_PINENTRY
1090 if (pwm->_password) {
1091 reset_async(pwm, 0);
1092 pwm->lastcmd = ASYNC_CMD_OPEN2;
1093 *rc = pwmd_open_async2(pwm, pwm->filename);
1095 else {
1096 #endif
1097 reset_async(pwm, 0);
1098 pwm->lastcmd = ASYNC_CMD_OPEN;
1099 *rc = pwmd_open_async(pwm, pwm->filename);
1100 #ifdef WITH_PINENTRY
1102 #endif
1105 done:
1106 if (*rc || pwm->state == ASYNC_DONE)
1107 return reset_async(pwm, 0);
1109 return pwm->state;
1112 gpg_error_t _assuan_command(pwm_t *pwm, assuan_context_t ctx,
1113 char **result, const char *cmd)
1115 membuf_t data;
1116 gpg_error_t rc;
1118 if (!cmd || !*cmd)
1119 return GPG_ERR_INV_ARG;
1121 if (strlen(cmd) >= ASSUAN_LINELENGTH+1)
1122 return GPG_ERR_LINE_TOO_LONG;
1124 data.len = 0;
1125 data.buf = NULL;
1126 rc = assuan_transact(ctx, cmd, inquire_realloc_cb, &data,
1127 #ifdef WITH_QUALITY
1128 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1129 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1130 #else
1131 inquire_cb, pwm,
1132 #endif
1133 pwm->status_func, pwm->status_data);
1135 if (rc) {
1136 if (data.buf) {
1137 pwmd_free(data.buf);
1138 data.buf = NULL;
1141 else {
1142 if (data.buf) {
1143 inquire_realloc_cb(&data, "", 1);
1145 if (!result) {
1146 pwmd_free(data.buf);
1147 rc = GPG_ERR_INV_ARG;
1149 else
1150 *result = (char *)data.buf;
1154 return gpg_err_code(rc);
1157 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_cb_t fn,
1158 void *data)
1160 if (!pwm || !cmd || !fn)
1161 return GPG_ERR_INV_ARG;
1163 if (!pwm->ctx)
1164 return GPG_ERR_INV_STATE;
1166 pwm->inquire_func = fn;
1167 pwm->inquire_data = data;
1168 pwm->inquire_sent = 0;
1169 return _assuan_command(pwm, pwm->ctx, NULL, cmd);
1172 gpg_error_t pwmd_command_ap(pwm_t *pwm, char **result, const char *cmd,
1173 va_list ap)
1175 char *buf;
1176 size_t len;
1177 va_list ap2;
1179 if (!pwm || !cmd)
1180 return GPG_ERR_INV_ARG;
1182 if (!pwm->ctx)
1183 return GPG_ERR_INV_STATE;
1186 * C99 allows the dst pointer to be null which will calculate the length
1187 * of the would-be result and return it.
1189 va_copy(ap2, ap);
1190 len = vsnprintf(NULL, 0, cmd, ap)+1;
1191 buf = (char *)pwmd_malloc(len);
1193 if (!buf) {
1194 va_end(ap2);
1195 return GPG_ERR_ENOMEM;
1198 len = vsnprintf(buf, len, cmd, ap2);
1199 va_end(ap2);
1201 if (buf[strlen(buf)-1] == '\n')
1202 buf[strlen(buf)-1] = 0;
1204 if (buf[strlen(buf)-1] == '\r')
1205 buf[strlen(buf)-1] = 0;
1207 gpg_error_t rc = _assuan_command(pwm, pwm->ctx, result, buf);
1208 pwmd_free(buf);
1209 return rc;
1212 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
1214 va_list ap;
1216 if (!pwm || !cmd)
1217 return GPG_ERR_INV_ARG;
1219 if (!pwm->ctx)
1220 return GPG_ERR_INV_STATE;
1222 if (result)
1223 *result = NULL;
1225 va_start(ap, cmd);
1226 gpg_error_t rc = pwmd_command_ap(pwm, result, cmd, ap);
1227 va_end(ap);
1228 return rc;
1231 static gpg_error_t send_pinentry_options(pwm_t *pwm)
1233 gpg_error_t rc;
1235 if (pwm->pinentry_path) {
1236 rc = pwmd_command(pwm, NULL, "SET PINENTRY_PATH=%s",
1237 pwm->pinentry_path);
1239 if (rc)
1240 return rc;
1243 if (pwm->pinentry_tty) {
1244 rc = pwmd_command(pwm, NULL, "SET TTYNAME=%s", pwm->pinentry_tty);
1246 if (rc)
1247 return rc;
1250 if (pwm->pinentry_term) {
1251 rc = pwmd_command(pwm, NULL, "SET TTYTYPE=%s", pwm->pinentry_term);
1253 if (rc)
1254 return rc;
1257 if (pwm->pinentry_display) {
1258 rc = pwmd_command(pwm, NULL, "SET DISPLAY=%s",
1259 pwm->pinentry_display);
1261 if (rc)
1262 return rc;
1265 if (pwm->title) {
1266 rc = pwmd_command(pwm, NULL, "SET TITLE=%s", pwm->title);
1268 if (rc)
1269 return rc;
1272 if (pwm->desc) {
1273 rc = pwmd_command(pwm, NULL, "SET DESC=%s", pwm->desc);
1275 if (rc)
1276 return rc;
1279 if (pwm->prompt) {
1280 rc = pwmd_command(pwm, NULL, "SET PROMPT=%s", pwm->prompt);
1282 if (rc)
1283 return rc;
1286 if (pwm->lcctype) {
1287 rc = pwmd_command(pwm, NULL, "SET LC_CTYPE=%s", pwm->lcctype);
1289 if (rc)
1290 return rc;
1293 if (pwm->lcmessages) {
1294 rc = pwmd_command(pwm, NULL, "SET LC_MESSAGES=%s", pwm->lcmessages);
1296 if (rc)
1297 return rc;
1300 if (pwm->pinentry_timeout >= 0 && !pwm->pin_try) {
1301 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=%i",
1302 pwm->pinentry_timeout);
1304 if (rc)
1305 return rc;
1308 return 0;
1311 gpg_error_t pwmd_socket_type(pwm_t *pwm, pwmd_socket_t *result)
1313 if (!pwm || !result)
1314 return GPG_ERR_INV_ARG;
1316 #ifdef WITH_TCP
1317 if ((pwm->fd == -1 && !pwm->tcp_conn) ||
1318 (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1))
1319 #else
1320 if (pwm->fd == -1)
1321 #endif
1322 return GPG_ERR_INV_STATE;
1324 #ifdef WITH_TCP
1325 *result = pwm->tcp_conn ? PWMD_SOCKET_SSH : PWMD_SOCKET_LOCAL;
1326 #else
1327 *result = PWMD_SOCKET_LOCAL;
1328 #endif
1329 return 0;
1332 static gpg_error_t set_pinentry_retry(pwm_t *pwm)
1334 gpg_error_t rc = 0;
1336 if (pwm->pin_try == 1) {
1337 rc = pwmd_command(pwm, NULL, "SET TITLE=%s",
1338 N_("Invalid passphrase, please try again."));
1340 if (rc)
1341 return rc;
1343 rc = pwmd_command(pwm, NULL, "SET PINENTRY_TIMEOUT=0");
1346 return rc;
1349 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result)
1351 gpg_error_t rc = GPG_ERR_NO_DATA;
1353 if (result)
1354 *result = NULL;
1355 else {
1356 if (pwm->password || pwm->passfunc)
1357 return 0;
1360 if (pwm->password) {
1361 rc = 0;
1362 *result = pwm->password;
1364 else if (pwm->passfunc)
1365 rc = pwm->passfunc(pwm->passdata, result);
1367 return rc;
1370 static gpg_error_t do_pwmd_open(pwm_t *pwm, const char *filename, int nb,
1371 int local_pinentry)
1373 char *result = NULL;
1374 char *password = NULL;
1375 gpg_error_t rc;
1376 int no_pinentry = 0;
1378 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1379 pwm->pin_try = 0;
1381 if (!pwm || !filename || !*filename)
1382 return GPG_ERR_INV_ARG;
1384 if (!pwm->ctx)
1385 return GPG_ERR_INV_STATE;
1388 * Avoid calling pinentry if the password is cached on the server or if
1389 * this is a new file.
1391 rc = pwmd_command(pwm, &result, "ISCACHED %s", filename);
1393 if (rc == GPG_ERR_ENOENT)
1394 goto gotpassword;
1396 if (rc && rc != GPG_ERR_NOT_FOUND)
1397 return rc;
1399 if (rc == GPG_ERR_NOT_FOUND) {
1400 rc = get_custom_passphrase(pwm, &password);
1402 if (rc && rc != GPG_ERR_NO_DATA)
1403 return rc;
1404 else if (rc == GPG_ERR_NO_DATA)
1405 rc = GPG_ERR_NOT_FOUND;
1406 else
1407 goto gotpassword;
1410 #ifdef WITH_PINENTRY
1411 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1412 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1413 if (!pwm->pin_try)
1414 no_pinentry = 1;
1416 rc = _pinentry_open(pwm, filename, &password, nb);
1418 /* pwmd_process() should be called if using a non-blocking local
1419 * pinentry. */
1420 if (rc || (!rc && nb))
1421 return rc;
1423 #endif
1425 gotpassword:
1426 reset_async(pwm, 0);
1428 #ifdef WITH_TCP
1429 if (!local_pinentry && !pwm->tcp_conn && !pwm->pin_try) {
1430 #else
1431 if (!local_pinentry && !pwm->pin_try) {
1432 #endif
1433 rc = send_pinentry_options(pwm);
1435 if (rc)
1436 return rc;
1439 rc = pwmd_command(pwm, NULL, "OPEN %s%s%s%s %s",
1440 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1441 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1442 no_pinentry ? "--pinentry=0 " : "",
1443 filename, password ? password : "");
1446 * Keep the user defined password set with pwmd_setopt(). The password may
1447 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1449 if (!pwm->passfunc && password && password != pwm->password)
1450 pwmd_free(password);
1452 if (rc == GPG_ERR_INV_PASSPHRASE) {
1453 if (++pwm->pin_try < pwm->pinentry_tries) {
1454 if (!get_custom_passphrase(pwm, NULL))
1455 goto done;
1457 #ifdef WITH_PINENTRY
1458 #ifdef WITH_TCP
1459 if (pwm->tcp_conn && !local_pinentry)
1460 return rc;
1461 else if (local_pinentry)
1462 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1463 else
1464 #else
1465 if (local_pinentry)
1466 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1467 else
1468 #endif
1469 #else
1470 #ifdef WITH_TCP
1471 if (pwm->tcp_conn)
1472 return rc;
1473 else
1474 #endif
1475 #endif
1476 rc = set_pinentry_retry(pwm);
1478 if (rc)
1479 return rc;
1481 goto gotpassword;
1483 #ifdef WITH_PINENTRY
1484 else if (local_pinentry)
1485 _pinentry_disconnect(pwm);
1486 #endif
1488 done:
1489 return rc;
1491 #ifdef WITH_PINENTRY
1492 else if (rc && local_pinentry)
1493 _pinentry_disconnect(pwm);
1494 #endif
1496 if (!rc) {
1497 if (pwm->filename)
1498 pwmd_free(pwm->filename);
1500 pwm->filename = pwmd_strdup(filename);
1503 return rc;
1506 gpg_error_t pwmd_open2(pwm_t *pwm, const char *filename)
1508 #ifndef WITH_PINENTRY
1509 return GPG_ERR_NOT_IMPLEMENTED;
1510 #else
1511 return do_pwmd_open(pwm, filename, 0, 1);
1512 #endif
1515 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
1517 return do_pwmd_open(pwm, filename, 0, 0);
1520 gpg_error_t pwmd_open_async2(pwm_t *pwm, const char *filename)
1522 #ifndef WITH_PINENTRY
1523 return GPG_ERR_NOT_IMPLEMENTED;
1524 #else
1525 if (!pwm || !filename)
1526 return GPG_ERR_INV_ARG;
1528 if (!pwm->ctx)
1529 return GPG_ERR_INV_STATE;
1531 if (pwm->cmd != ASYNC_CMD_NONE)
1532 return GPG_ERR_ASS_NESTED_COMMANDS;
1534 /* Initialize a new command since this is not a pinentry retry. */
1535 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1536 pwm->pin_try = 0;
1538 pwm->cmd = ASYNC_CMD_OPEN2;
1539 pwm->state = ASYNC_PROCESS;
1540 gpg_error_t rc = do_pwmd_open(pwm, filename, 1, 1);
1542 if (rc)
1543 reset_async(pwm, 0);
1545 return rc;
1546 #endif
1549 struct open_inquire_s {
1550 pwm_t *pwm;
1551 char *filename;
1552 pwmd_inquire_cb_t func;
1553 void *user;
1554 int sent;
1557 /* We need to send the filename argument here rather than confusing the app.
1558 * The app will only send the passphrase and nothing else.
1560 static gpg_error_t open_inquire_cb(void *user, const char *cmd,
1561 gpg_error_t rc, char **data, size_t *len)
1563 struct open_inquire_s *o = user;
1565 if (rc)
1566 return rc;
1568 if (!o->sent) {
1569 char *line = pwmd_strdup_printf("%s ", o->filename);
1570 rc = assuan_send_data(o->pwm->ctx, line, strlen(line));
1572 pwmd_free(line);
1574 /* Give the user a chance to cleanup. */
1575 if (rc)
1576 return o->func(o->user, cmd, rc, data, len);
1578 o->sent = 1;
1581 return o->func(o->user, cmd, rc, data, len);
1584 gpg_error_t pwmd_open_inquire(pwm_t *pwm, const char *filename,
1585 pwmd_inquire_cb_t func, void *user)
1587 if (!pwm || !filename || !func)
1588 return GPG_ERR_INV_ARG;
1590 if (!pwm->ctx)
1591 return GPG_ERR_INV_STATE;
1593 struct open_inquire_s *inq = pwmd_calloc(1, sizeof(struct open_inquire_s));
1594 gpg_error_t rc;
1596 if (!inq)
1597 return GPG_ERR_ENOMEM;
1599 inq->pwm = pwm;
1600 inq->filename = pwmd_strdup(filename);
1601 inq->func = func;
1602 inq->user = user;
1604 char *cmd = pwmd_strdup_printf("OPEN --inquire %s%s",
1605 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1606 (pwm->opts & OPT_BASE64) ? "--base64 " : "");
1608 rc = pwmd_inquire(pwm, cmd, open_inquire_cb, inq);
1609 pwmd_free(cmd);
1610 pwmd_free(inq->filename);
1611 pwmd_free(inq);
1613 if (!rc) {
1614 if (pwm->filename)
1615 pwmd_free(pwm->filename);
1617 pwm->filename = pwmd_strdup(filename);
1619 if (!pwm->filename) {
1620 pwmd_close(pwm);
1621 rc = GPG_ERR_ENOMEM;
1625 return rc;
1628 gpg_error_t pwmd_save_inquire(pwm_t *pwm, pwmd_inquire_cb_t func, void *user)
1630 if (!pwm || !func)
1631 return GPG_ERR_INV_ARG;
1633 if (!pwm->ctx)
1634 return GPG_ERR_INV_STATE;
1636 gpg_error_t rc;
1637 char *tmp = pwmd_strdup_printf("%li", pwm->iterations);
1638 char *cmd = pwmd_strdup_printf("SAVE %s --inquire --iterations=%s --cipher=%s",
1639 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1640 pwm->iterations != -1 ? tmp : "",
1641 pwm->cipher ? pwm->cipher : "");
1643 rc = pwmd_inquire(pwm, cmd, func, user);
1644 pwmd_free(cmd);
1645 return rc;
1648 static gpg_error_t do_pwmd_save(pwm_t *pwm, int nb, int local_pinentry)
1650 char *result = NULL;
1651 char *password = NULL;
1652 gpg_error_t rc;
1654 if (!pwm)
1655 return GPG_ERR_INV_ARG;
1657 if (!pwm->ctx)
1658 return GPG_ERR_INV_STATE;
1660 rc = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1662 if (rc == GPG_ERR_ENOENT)
1663 rc = GPG_ERR_NOT_FOUND;
1665 if (rc && rc != GPG_ERR_NOT_FOUND)
1666 return rc;
1668 if (rc == GPG_ERR_NOT_FOUND) {
1669 rc = get_custom_passphrase(pwm, &password);
1671 if (rc && rc != GPG_ERR_NO_DATA)
1672 return rc;
1673 else if (rc == GPG_ERR_NO_DATA)
1674 rc = GPG_ERR_NOT_FOUND;
1675 else
1676 goto gotpassword;
1679 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1680 #ifdef WITH_PINENTRY
1681 /* Get the password using the LOCAL pinentry. */
1682 if (nb) {
1683 int p[2];
1684 pid_t pid;
1685 pwmd_nb_status_t pw;
1687 if (pipe(p) == -1)
1688 return gpg_error_from_syserror();
1690 #ifdef WITH_LIBPTH
1691 pid = pth_fork();
1692 #else
1693 pid = fork();
1694 #endif
1696 switch (pid) {
1697 case 0:
1698 close(p[0]);
1699 pw.fd = p[0];
1700 password = NULL;
1701 pw.error = _do_save_getpin(pwm, &password);
1703 if (!pw.error) {
1704 snprintf(pw.password, sizeof(pw.password), "%s",
1705 password);
1706 pwmd_free(password);
1708 #ifdef WITH_LIBPTH
1709 pth_write(p[1], &pw, sizeof(pw));
1710 #else
1711 write(p[1], &pw, sizeof(pw));
1712 #endif
1713 memset(&pw, 0, sizeof(pw));
1714 close(p[1]);
1715 _exit(0);
1716 break;
1717 case -1:
1718 rc = gpg_error_from_syserror();
1719 close(p[0]);
1720 close(p[1]);
1721 return rc;
1722 default:
1723 break;
1726 close(p[1]);
1727 pwm->nb_fd = p[0];
1728 pwm->nb_pid = pid;
1729 return 0;
1732 rc = _do_save_getpin(pwm, &password);
1734 if (rc)
1735 return rc;
1736 #endif
1738 else
1739 pwm->state = ASYNC_DONE;
1741 gotpassword:
1742 reset_async(pwm, 0);
1744 #ifdef WITH_TCP
1745 if (!local_pinentry && !pwm->tcp_conn) {
1746 #else
1747 if (!local_pinentry) {
1748 #endif
1749 rc = send_pinentry_options(pwm);
1751 if (rc)
1752 return rc;
1755 char *tmp = pwmd_strdup_printf("%li", pwm->iterations);
1757 #ifdef WITH_TCP
1758 rc = pwmd_command(pwm, NULL, "SAVE %s%s--iterations=%s --cipher=%s %s",
1759 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1760 local_pinentry || pwm->tcp_conn ? "--pinentry=0 " : "",
1761 pwm->iterations != -1 ? tmp : "",
1762 pwm->cipher ? pwm->cipher : "",
1763 password ? password : "");
1764 #else
1765 rc = pwmd_command(pwm, NULL, "SAVE %s--iterations=%s --cipher=%s %s",
1766 (pwm->opts & OPT_BASE64) ? "--base64 " : "",
1767 pwm->iterations != -1 ? tmp : "",
1768 pwm->cipher ? pwm->cipher : "",
1769 password ? password : "");
1770 #endif
1772 pwmd_free(tmp);
1774 if (!pwm->passfunc && password && password != pwm->password)
1775 pwmd_free(password);
1777 return rc;
1780 gpg_error_t pwmd_save_async2(pwm_t *pwm)
1782 #ifndef WITH_PINENTRY
1783 return GPG_ERR_NOT_IMPLEMENTED;
1784 #else
1785 if (!pwm)
1786 return GPG_ERR_INV_ARG;
1788 if (!pwm->ctx)
1789 return GPG_ERR_INV_STATE;
1791 if (pwm->cmd != ASYNC_CMD_NONE)
1792 return GPG_ERR_ASS_NESTED_COMMANDS;
1794 pwm->cmd = ASYNC_CMD_SAVE2;
1795 pwm->state = ASYNC_PROCESS;
1796 gpg_error_t rc = do_pwmd_save(pwm, 1, 1);
1798 if (rc)
1799 reset_async(pwm, 0);
1801 return rc;
1802 #endif
1805 gpg_error_t pwmd_save2(pwm_t *pwm)
1807 #ifndef WITH_PINENTRY
1808 return GPG_ERR_NOT_IMPLEMENTED;
1809 #else
1810 return do_pwmd_save(pwm, 0, 1);
1811 #endif
1814 gpg_error_t pwmd_save(pwm_t *pwm)
1816 return do_pwmd_save(pwm, 0, 0);
1819 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1821 va_list ap;
1822 int n;
1823 char *arg1;
1824 gpg_error_t rc = 0;
1826 if (!pwm)
1827 return GPG_ERR_INV_ARG;
1829 va_start(ap, opt);
1831 switch (opt) {
1832 case PWMD_OPTION_BASE64:
1833 n = va_arg(ap, int);
1835 if (n < 0 || n > 1) {
1836 rc = GPG_ERR_INV_VALUE;
1837 break;
1840 if (n)
1841 pwm->opts |= OPT_BASE64;
1842 else
1843 pwm->opts &= ~OPT_BASE64;
1845 break;
1846 case PWMD_OPTION_ITERATIONS:
1847 pwm->iterations = va_arg(ap, long);
1849 if (pwm->iterations < -1) {
1850 pwm->iterations = -1;
1851 rc = GPG_ERR_INV_VALUE;
1854 break;
1855 case PWMD_OPTION_CIPHER:
1856 arg1 = va_arg(ap, char *);
1858 if (pwm->cipher)
1859 pwmd_free(pwm->cipher);
1861 pwm->cipher = arg1 ? pwmd_strdup(arg1) : NULL;
1862 break;
1863 case PWMD_OPTION_LOCK_ON_OPEN:
1864 n = va_arg(ap, int);
1866 if (n < 0 || n > 1)
1867 rc = GPG_ERR_INV_VALUE;
1869 if (n)
1870 pwm->opts |= OPT_LOCK_ON_OPEN;
1871 else
1872 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1874 break;
1875 case PWMD_OPTION_INQUIRE_TOTAL:
1876 pwm->inquire_total = va_arg(ap, size_t);
1877 break;
1878 case PWMD_OPTION_STATUS_CB:
1879 pwm->status_func = va_arg(ap, pwmd_status_cb_t);
1880 break;
1881 case PWMD_OPTION_STATUS_DATA:
1882 pwm->status_data = va_arg(ap, void *);
1883 break;
1884 case PWMD_OPTION_PASSPHRASE_CB:
1885 pwm->passfunc = va_arg(ap, pwmd_passphrase_cb_t);
1886 break;
1887 case PWMD_OPTION_PASSPHRASE_DATA:
1888 pwm->passdata = va_arg(ap, void *);
1889 break;
1890 case PWMD_OPTION_PASSPHRASE:
1891 arg1 = va_arg(ap, char *);
1893 if (pwm->password)
1894 pwmd_free(pwm->password);
1896 pwm->password = arg1 ? pwmd_strdup(arg1) : NULL;
1897 break;
1898 case PWMD_OPTION_PINENTRY_TRIES:
1899 n = va_arg(ap, int);
1901 if (n <= 0)
1902 rc = GPG_ERR_INV_VALUE;
1903 else
1904 pwm->pinentry_tries = n;
1906 break;
1907 case PWMD_OPTION_PINENTRY_TIMEOUT:
1908 n = va_arg(ap, int);
1910 if (n < 0)
1911 rc = GPG_ERR_INV_VALUE;
1912 else
1913 pwm->pinentry_timeout = n;
1915 break;
1916 case PWMD_OPTION_PINENTRY_PATH:
1917 if (pwm->pinentry_path)
1918 pwmd_free(pwm->pinentry_path);
1920 pwm->pinentry_path = _expand_homedir(va_arg(ap, char *), NULL);
1921 break;
1922 case PWMD_OPTION_PINENTRY_TTY:
1923 arg1 = va_arg(ap, char *);
1925 if (pwm->pinentry_tty)
1926 pwmd_free(pwm->pinentry_tty);
1928 pwm->pinentry_tty = arg1 ? pwmd_strdup(arg1) : NULL;
1929 break;
1930 case PWMD_OPTION_PINENTRY_DISPLAY:
1931 if (pwm->pinentry_display)
1932 pwmd_free(pwm->pinentry_display);
1934 pwm->pinentry_display = pwmd_strdup(va_arg(ap, char *));
1935 break;
1936 case PWMD_OPTION_PINENTRY_TERM:
1937 arg1 = va_arg(ap, char *);
1939 if (pwm->pinentry_term)
1940 pwmd_free(pwm->pinentry_term);
1942 pwm->pinentry_term = arg1 ? pwmd_strdup(arg1) : NULL;
1943 break;
1944 case PWMD_OPTION_PINENTRY_TITLE:
1945 if (pwm->title)
1946 pwmd_free(pwm->title);
1948 pwm->title = _percent_escape(va_arg(ap, char *));
1949 break;
1950 case PWMD_OPTION_PINENTRY_PROMPT:
1951 if (pwm->prompt)
1952 pwmd_free(pwm->prompt);
1954 pwm->prompt = _percent_escape(va_arg(ap, char *));
1955 break;
1956 case PWMD_OPTION_PINENTRY_DESC:
1957 if (pwm->desc)
1958 pwmd_free(pwm->desc);
1960 pwm->desc = _percent_escape(va_arg(ap, char *));
1961 break;
1962 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1963 arg1 = va_arg(ap, char *);
1965 if (pwm->lcctype)
1966 pwmd_free(pwm->lcctype);
1968 pwm->lcctype = arg1 ? pwmd_strdup(arg1) : NULL;
1969 break;
1970 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1971 arg1 = va_arg(ap, char *);
1973 if (pwm->lcmessages)
1974 pwmd_free(pwm->lcmessages);
1976 pwm->lcmessages = arg1 ? pwmd_strdup(arg1) : NULL;
1977 break;
1978 #ifdef WITH_TCP
1979 case PWMD_OPTION_IP_VERSION:
1980 n = va_arg(ap, int);
1982 switch (n) {
1983 case PWMD_IP_ANY:
1984 case PWMD_IPV4:
1985 case PWMD_IPV6:
1986 pwm->prot = n;
1987 break;
1988 default:
1989 rc = GPG_ERR_INV_VALUE;
1990 break;
1992 break;
1993 case PWMD_OPTION_KNOWNHOST_CB:
1994 pwm->kh_cb = va_arg(ap, pwmd_knownhost_cb_t);
1995 break;
1996 case PWMD_OPTION_KNOWNHOST_DATA:
1997 pwm->kh_data = va_arg(ap, void *);
1998 break;
1999 case PWMD_OPTION_SSH_AGENT:
2000 pwm->use_agent = va_arg(ap, int);
2002 if (pwm->use_agent < 0 || pwm->use_agent > 1) {
2003 pwm->use_agent = 0;
2004 rc = GPG_ERR_INV_VALUE;
2007 break;
2008 #else
2009 case PWMD_OPTION_IP_VERSION:
2010 case PWMD_OPTION_KNOWNHOST_CB:
2011 case PWMD_OPTION_KNOWNHOST_DATA:
2012 case PWMD_OPTION_SSH_AGENT:
2013 rc = GPG_ERR_NOT_IMPLEMENTED;
2014 break;
2015 #endif
2016 default:
2017 rc = GPG_ERR_UNKNOWN_OPTION;
2018 break;
2021 va_end(ap);
2022 return rc;
2025 gpg_error_t pwmd_get_fds(pwm_t *pwm, pwmd_fd_t *fds, int *n_fds)
2027 int in_total;
2028 int fd = 0;
2029 #ifdef WITH_TCP
2030 int afds[ARES_GETSOCK_MAXNUM];
2031 int got_sock = 0;
2032 int n, i;
2033 #endif
2035 if (!pwm || !fds || !n_fds || *n_fds <= 0)
2036 return GPG_ERR_INV_ARG;
2038 in_total = *n_fds;
2039 #ifdef WITH_TCP
2040 memset(afds, 0, sizeof(int)*ARES_GETSOCK_MAXNUM);
2041 #endif
2042 memset(fds, 0, sizeof(pwmd_fd_t)*in_total);
2043 *n_fds = 0;
2045 switch (pwm->cmd) {
2046 default:
2047 case ASYNC_CMD_NONE:
2048 case ASYNC_CMD_OPEN:
2049 case ASYNC_CMD_SAVE:
2050 #ifdef WITH_PINENTRY
2051 async1:
2052 #endif
2053 if (pwm->fd == -1)
2054 return GPG_ERR_INV_STATE;
2056 (*n_fds)++;
2057 fds[fd].fd = pwm->fd;
2058 fds[fd++].flags = PWMD_FD_READABLE;
2059 return 0;
2060 #ifdef WITH_PINENTRY
2061 case ASYNC_CMD_OPEN2:
2062 case ASYNC_CMD_SAVE2:
2063 /* The command has already completed (cached or new). */
2064 if (pwm->state == ASYNC_DONE)
2065 return 0;
2067 if (pwm->nb_fd == -1)
2068 return GPG_ERR_INV_STATE;
2070 (*n_fds)++;
2071 fds[fd].fd = pwm->nb_fd;
2072 fds[fd++].flags = PWMD_FD_READABLE;
2073 goto async1;
2074 #endif
2075 #ifdef WITH_TCP
2076 case ASYNC_CMD_DNS:
2077 if (!pwm->tcp_conn || !pwm->tcp_conn->chan)
2078 return GPG_ERR_INV_STATE;
2080 n = ares_getsock(pwm->tcp_conn->chan, afds, ARES_GETSOCK_MAXNUM);
2082 for (i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
2083 got_sock = 0;
2085 if (fd > in_total) {
2086 *n_fds = fd;
2087 return GPG_ERR_ERANGE;
2090 if (ARES_GETSOCK_READABLE(n, i)) {
2091 got_sock++;
2092 fds[fd].flags |= PWMD_FD_READABLE;
2095 if (ARES_GETSOCK_WRITABLE(n, i)) {
2096 got_sock++;
2097 fds[fd].flags |= PWMD_FD_WRITABLE;
2100 if (got_sock)
2101 fds[fd++].fd = afds[i];
2104 *n_fds = fd;
2105 return 0;
2106 case ASYNC_CMD_CONNECT:
2107 case ASYNC_CMD_HOSTKEY:
2108 if (!pwm->tcp_conn || pwm->tcp_conn->fd == -1)
2109 return GPG_ERR_INV_STATE;
2111 (*n_fds)++;
2112 fds[fd].fd = pwm->tcp_conn->fd;
2113 fds[fd++].flags = PWMD_FD_READABLE;
2114 return 0;
2115 #endif
2118 return GPG_ERR_INV_STATE;
2121 pwm_t *pwmd_new(const char *name)
2123 pwm_t *h = pwmd_calloc(1, sizeof(pwm_t));
2125 if (!h)
2126 return NULL;
2128 if (name) {
2129 h->name = pwmd_strdup(name);
2131 if (!h->name) {
2132 pwmd_free(h);
2133 return NULL;
2137 reset_handle(h);
2138 h->pinentry_timeout = -30;
2139 h->pinentry_tries = 3;
2140 h->iterations = -1;
2141 #ifdef WITH_TCP
2142 h->prot = PWMD_IP_ANY;
2143 #endif
2145 if (ttyname(STDOUT_FILENO)) {
2146 char buf[256];
2148 ttyname_r(STDOUT_FILENO, buf, sizeof(buf));
2149 h->pinentry_tty = pwmd_strdup(buf);
2151 if (!h->pinentry_tty)
2152 goto fail;
2155 if (getenv("TERM") && h->pinentry_tty) {
2156 h->pinentry_term = pwmd_strdup(getenv("TERM"));
2158 if (!h->pinentry_term)
2159 goto fail;
2162 if (getenv("DISPLAY")) {
2163 h->pinentry_display = pwmd_strdup(getenv("DISPLAY"));
2165 if (!h->pinentry_display)
2166 goto fail;
2169 return h;
2171 fail:
2172 pwmd_close(h);
2173 return NULL;
2176 void pwmd_free(void *ptr)
2178 _xfree(ptr);
2181 void *pwmd_malloc(size_t size)
2183 return _xmalloc(size);
2186 void *pwmd_calloc(size_t nmemb, size_t size)
2188 return _xcalloc(nmemb, size);
2191 void *pwmd_realloc(void *ptr, size_t size)
2193 return _xrealloc(ptr, size);
2196 char *pwmd_strdup(const char *str)
2198 return _xstrdup(str);
2201 char *pwmd_strdup_printf(const char *fmt, ...)
2203 va_list ap, ap2;
2204 int len;
2205 char *buf;
2207 if (!fmt)
2208 return NULL;
2210 va_start(ap, fmt);
2211 va_copy(ap2, ap);
2212 len = vsnprintf(NULL, 0, fmt, ap);
2213 va_end(ap);
2214 buf = pwmd_malloc(++len);
2216 if (buf)
2217 vsnprintf(buf, len, fmt, ap2);
2219 va_end(ap2);
2220 return buf;
2223 gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result,
2224 pwmd_pinentry_t which)
2226 #ifndef WITH_PINENTRY
2227 return GPG_ERR_NOT_IMPLEMENTED;
2228 #else
2229 return _pwmd_getpin(pwm, filename, result, which);
2230 #endif
2233 const char *pwmd_version()
2235 return LIBPWMD_VERSION_STR;