Added pwmd_getpin(). This won't send any commands to the server. May be
[libpwmd.git] / src / libpwmd.c
blobcd702cb967a4b875c81f8ccbd164f8ce5d9429b6
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <sys/wait.h>
32 #include <fcntl.h>
33 #include <pwd.h>
34 #include <time.h>
35 #include <sys/types.h>
36 #include <limits.h>
37 #include <sys/select.h>
38 #include <libpwmd.h>
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
44 #ifdef HAVE_ASSUAN_H
45 #include <assuan.h>
46 #endif
48 #include "mem.h"
49 #include "misc.h"
50 #include "types.h"
52 #ifdef WITH_PINENTRY
53 #include "pinentry.h"
54 #endif
56 #ifdef WITH_TCP
57 #include "ssh.h"
58 #endif
60 static gpg_error_t send_pinentry_options(pwm_t *pwm);
61 static gpg_error_t _pwmd_process(pwm_t *pwm);
62 static gpg_error_t set_pinentry_retry(pwm_t *pwm);
63 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result);
65 static const char *_pwmd_strerror(gpg_error_t e)
67 gpg_err_code_t code = gpg_err_code(e);
69 if (code >= GPG_ERR_USER_1 && code < gpg_err_code(EPWMD_MAX)) {
70 switch (code) {
71 default:
72 return NULL;
73 case GPG_ERR_USER_1:
74 return N_("Unknown error");
75 case GPG_ERR_USER_2:
76 return N_("No cache slots available");
77 case GPG_ERR_USER_3:
78 return N_("Recursion loop");
79 case GPG_ERR_USER_4:
80 return N_("No file is open");
81 case GPG_ERR_USER_5:
82 return N_("General LibXML error");
83 case GPG_ERR_USER_6:
84 return N_("File modified");
88 return NULL;
91 const char *pwmd_strerror(gpg_error_t code)
93 const char *p = _pwmd_strerror(code);
95 return p ? p : gpg_strerror(code);
98 int pwmd_strerror_r(gpg_error_t code, char *buf, size_t size)
100 const char *p = _pwmd_strerror(code);
102 if (p) {
103 snprintf(buf, size, "%s", p);
105 if (strlen(p) > size)
106 return ERANGE;
108 return 0;
111 return gpg_strerror_r(code, buf, size);
114 gpg_error_t pwmd_init()
116 static int initialized;
118 if (initialized)
119 return 0;
121 #ifndef MEM_DEBUG
122 _xmem_init();
123 #endif
124 #ifdef ENABLE_NLS
125 bindtextdomain("libpwmd", LOCALEDIR);
126 #endif
127 gpg_err_init();
128 assuan_set_malloc_hooks(pwmd_malloc, pwmd_realloc, pwmd_free);
129 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
130 initialized = 1;
131 return 0;
134 gpg_error_t _connect_finalize(pwm_t *pwm)
136 int active[2];
137 int n = assuan_get_active_fds(pwm->ctx, 0, active, N_ARRAY(active));
138 gpg_error_t rc;
139 char *result;
141 if (n <= 0)
142 return GPG_ERR_EBADFD;
144 pwm->fd = active[0];
145 #ifdef WITH_PINENTRY
146 pwm->pid = -1;
147 #endif
148 assuan_set_pointer(pwm->ctx, pwm);
150 #ifdef WITH_TCP
151 // Until X11 forwarding is supported, disable the remote pwmd pinentry.
152 if (pwm->tcp_conn) {
153 rc = pwmd_command(pwm, NULL, "OPTION PINENTRY=0");
155 if (rc)
156 return rc;
158 #endif
160 if (pwm->name) {
161 rc = pwmd_command(pwm, NULL, "OPTION CLIENT NAME=%s", pwm->name);
163 if (rc)
164 return rc;
167 rc = pwmd_command(pwm, &result, "VERSION");
169 if (rc && rc != GPG_ERR_ASS_UNKNOWN_CMD)
170 return rc;
172 if (rc)
173 pwm->version = PWMD_V1;
174 else
175 pwm->version = PWMD_V2;
177 pwmd_free(result);
178 return 0;
181 static gpg_error_t _pwmd_connect_url(pwm_t *pwm, const char *url, int async)
183 char *p = (char *)url;
184 gpg_error_t rc;
186 if (!pwm)
187 return GPG_ERR_INV_ARG;
189 if (!p || !strncmp(p, "socket://", 9)) {
190 if (p)
191 p += 9;
193 goto connect_uds;
195 else if (!strncmp(p, "ssh://", 6) || !strncmp(p, "ssh6://", 7) ||
196 !strncmp(p, "ssh4://", 7)) {
197 #ifndef WITH_TCP
198 return GPG_ERR_NOT_IMPLEMENTED;
199 #else
200 char *host = NULL;
201 int port = -1;
202 char *identity = NULL;
203 char *known_hosts = NULL;
204 char *username = NULL;
206 if (!strncmp(p, "ssh6://", 7)) {
207 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV6);
208 p += 7;
210 else if (!strncmp(p, "ssh4://", 7)) {
211 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IPV4);
212 p += 7;
214 else {
215 rc = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, PWMD_IP_ANY);
216 p += 6;
219 if (rc)
220 return rc;
222 rc = _parse_ssh_url(p, &host, &port, &username, &identity,
223 &known_hosts);
225 if (rc)
226 goto fail;
228 if (async)
229 rc = pwmd_ssh_connect_async(pwm, host, port, identity, username,
230 known_hosts);
231 else
232 rc = pwmd_ssh_connect(pwm, host, port, identity, username,
233 known_hosts);
235 fail:
236 if (host)
237 pwmd_free(host);
239 if (username)
240 pwmd_free(username);
242 if (identity)
243 pwmd_free(identity);
245 if (known_hosts)
246 pwmd_free(known_hosts);
248 return rc;
249 #endif
252 connect_uds:
253 rc = pwmd_connect(pwm, p);
254 pwm->state = ASYNC_DONE;
255 return rc;
258 gpg_error_t pwmd_connect_url(pwm_t *pwm, const char *url)
260 return _pwmd_connect_url(pwm, url, 0);
263 gpg_error_t pwmd_connect_url_async(pwm_t *pwm, const char *url)
265 return _pwmd_connect_url(pwm, url, 1);
268 gpg_error_t pwmd_connect(pwm_t *pwm, const char *path)
270 char *socketpath = NULL;
271 assuan_context_t ctx;
272 struct passwd pw;
273 char *pwbuf;
274 gpg_error_t rc;
276 if (!pwm)
277 return GPG_ERR_INV_ARG;
279 pwbuf = _getpwuid(&pw);
281 if (!pwbuf)
282 return gpg_error_from_errno(errno);
284 if (!path || !*path)
285 socketpath = pwmd_strdup_printf("%s/.pwmd/socket", pw.pw_dir);
286 else
287 socketpath = _expand_homedir((char *)path, &pw);
289 pwmd_free(pwbuf);
291 if (!socketpath)
292 return gpg_error_from_errno(ENOMEM);
294 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
295 pwmd_free(socketpath);
297 if (rc)
298 return gpg_err_code(rc);
300 pwm->ctx = ctx;
301 return _connect_finalize(pwm);
304 static void disconnect(pwm_t *pwm)
306 if (!pwm || !pwm->ctx)
307 return;
309 assuan_disconnect(pwm->ctx);
310 pwm->ctx = NULL;
311 pwm->fd = -1;
314 void pwmd_close(pwm_t *pwm)
316 if (!pwm)
317 return;
319 disconnect(pwm);
321 if (pwm->password)
322 pwmd_free(pwm->password);
324 if (pwm->title)
325 pwmd_free(pwm->title);
327 if (pwm->desc)
328 pwmd_free(pwm->desc);
330 if (pwm->prompt)
331 pwmd_free(pwm->prompt);
333 if (pwm->pinentry_tty)
334 pwmd_free(pwm->pinentry_tty);
336 if (pwm->pinentry_display)
337 pwmd_free(pwm->pinentry_display);
339 if (pwm->pinentry_term)
340 pwmd_free(pwm->pinentry_term);
342 if (pwm->lcctype)
343 pwmd_free(pwm->lcctype);
345 if (pwm->lcmessages)
346 pwmd_free(pwm->lcmessages);
348 if (pwm->filename)
349 pwmd_free(pwm->filename);
351 if (pwm->name)
352 pwmd_free(pwm->name);
354 #ifdef WITH_TCP
355 if (pwm->tcp_conn)
356 _free_ssh_conn(pwm->tcp_conn);
357 #endif
359 pwmd_free(pwm);
362 gpg_error_t pwmd_ssh_connect_async(pwm_t *pwm, const char *host, int port,
363 const char *identity, const char *user, const char *known_hosts)
365 #ifndef WITH_TCP
366 return GPG_ERR_NOT_IMPLEMENTED;
367 #else
368 return _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
369 known_hosts, ASYNC_CMD_CONNECT);
370 #endif
373 gpg_error_t pwmd_ssh_connect(pwm_t *pwm, const char *host, int port,
374 const char *identity, const char *user, const char *known_hosts)
376 #ifndef WITH_TCP
377 return GPG_ERR_NOT_IMPLEMENTED;
378 #else
379 return _do_pwmd_ssh_connect(pwm, host, port, identity, user, known_hosts, 0);
380 #endif
383 gpg_error_t pwmd_get_hostkey(pwm_t *pwm, const char *host, int port,
384 char **result)
386 #ifndef WITH_TCP
387 return GPG_ERR_NOT_IMPLEMENTED;
388 #else
389 char *hostkey;
390 gpg_error_t rc;
392 rc = _do_pwmd_ssh_connect(pwm, host, port, NULL, NULL, NULL, 1);
394 if (rc)
395 return rc;
397 hostkey = pwmd_strdup(pwm->tcp_conn->hostkey);
399 if (!hostkey)
400 rc = gpg_error_from_errno(ENOMEM);
402 *result = hostkey;
403 return rc;
404 #endif
407 gpg_error_t pwmd_get_hostkey_async(pwm_t *pwm, const char *host, int port)
409 #ifndef WITH_TCP
410 return GPG_ERR_NOT_IMPLEMENTED;
411 #else
412 return _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
413 ASYNC_CMD_HOSTKEY);
414 #endif
417 static int inquire_realloc_cb(void *data, const void *buffer, size_t len)
419 membuf_t *mem = (membuf_t *)data;
420 void *p;
422 if (!buffer)
423 return 0;
425 if ((p = pwmd_realloc(mem->buf, mem->len + len)) == NULL)
426 return gpg_error_from_errno(ENOMEM);
428 mem->buf = p;
429 memcpy((char *)mem->buf + mem->len, buffer, len);
430 mem->len += len;
431 return 0;
434 static int inquire_cb(void *data, const char *keyword)
436 pwm_t *pwm = (pwm_t *)data;
437 gpg_error_t rc = 0;
438 int flags = fcntl(pwm->fd, F_GETFL);
440 /* Shouldn't get this far without a callback. */
441 if (!pwm->inquire_func)
442 return GPG_ERR_INV_ARG;
444 for (;;) {
445 char *result = NULL;
446 size_t len;
447 gpg_error_t arc;
449 rc = pwm->inquire_func(pwm->inquire_data, keyword, rc, &result, &len);
450 rc = gpg_err_code(rc);
452 if (rc == GPG_ERR_EOF || !rc) {
453 if (len <= 0 || !result) {
454 rc = 0;
455 break;
458 arc = assuan_send_data(pwm->ctx, result, len);
459 arc = gpg_err_code(arc);
461 if (rc == GPG_ERR_EOF) {
462 rc = arc;
463 break;
466 rc = arc;
468 else if (rc)
469 break;
471 if (!rc) {
472 /* Set to non-blocking so _pwmd_process() can return. */
473 fcntl(pwm->fd, F_SETFL, O_NONBLOCK);
474 rc = _pwmd_process(pwm);
475 fcntl(pwm->fd, F_SETFL, flags);
479 fcntl(pwm->fd, F_SETFL, flags);
480 return gpg_err_code(rc);
483 static gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, ...)
485 char *buf;
486 gpg_error_t rc;
487 va_list ap;
488 int len;
490 if (pwm->state == ASYNC_DONE)
491 pwm->state = ASYNC_INIT;
493 if (pwm->state != ASYNC_INIT)
494 return GPG_ERR_INV_STATE;
496 buf = pwmd_malloc(ASSUAN_LINELENGTH+1);
498 if (!buf)
499 return gpg_error_from_errno(ENOMEM);
501 va_start(ap, cmd);
502 len = vsnprintf(buf, ASSUAN_LINELENGTH+1, cmd, ap);
503 va_end(ap);
505 if (len >= ASSUAN_LINELENGTH+1) {
506 pwmd_free(buf);
507 return GPG_ERR_LINE_TOO_LONG;
510 rc = assuan_write_line(pwm->ctx, buf);
511 pwmd_free(buf);
513 if (!rc)
514 pwm->state = ASYNC_PROCESS;
516 return gpg_err_code(rc);
519 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
521 char *p = NULL;
522 const char *f = NULL;
523 gpg_error_t rc;
525 if (!pwm || !filename)
526 return GPG_ERR_INV_ARG;
528 if (!pwm->ctx)
529 return GPG_ERR_INV_STATE;
531 if (pwm->cmd != ASYNC_CMD_NONE)
532 return GPG_ERR_ASS_NESTED_COMMANDS;
534 if (pwm->lastcmd == ASYNC_CMD_NONE) {
535 pwm->pin_try = 0;
537 if (pwm->filename)
538 pwmd_free(pwm->filename);
540 pwm->filename = pwmd_strdup(filename);
542 if (!pwm->filename)
543 return gpg_error_from_errno(ENOMEM);
545 gpg_error_t rc = send_pinentry_options(pwm);
547 if (rc)
548 return rc;
550 rc = get_custom_passphrase(pwm, &p);
552 if (rc && rc != GPG_ERR_NO_DATA)
553 return rc;
555 f = filename;
557 #ifdef WITH_PINENTRY
558 else if (pwm->lastcmd == ASYNC_CMD_OPEN2) {
559 p = pwm->_password;
560 f = pwm->filename;
562 #endif
563 else if (pwm->lastcmd == ASYNC_CMD_OPEN) {
564 rc = set_pinentry_retry(pwm);
566 if (rc)
567 return rc;
569 p = pwm->password;
570 f = filename;
572 else
573 return GPG_ERR_INV_STATE;
575 pwm->cmd = ASYNC_CMD_OPEN;
576 return do_nb_command(pwm, "OPEN %s %s", f, p ? p : "");
579 gpg_error_t pwmd_save_async(pwm_t *pwm)
581 char *p = NULL;
583 if (!pwm)
584 return GPG_ERR_INV_ARG;
586 if (!pwm->ctx)
587 return GPG_ERR_INV_STATE;
589 if (pwm->cmd != ASYNC_CMD_NONE)
590 return GPG_ERR_ASS_NESTED_COMMANDS;
592 if (pwm->lastcmd != ASYNC_CMD_SAVE2) {
593 gpg_error_t rc = send_pinentry_options(pwm);
595 if (rc)
596 return rc;
598 rc = get_custom_passphrase(pwm, &p);
600 if (rc && rc != GPG_ERR_NO_DATA)
601 return rc;
603 #ifdef WITH_PINENTRY
604 else
605 p = pwm->_password;
606 #endif
608 pwm->cmd = ASYNC_CMD_SAVE;
609 return do_nb_command(pwm, "SAVE %s", p ? p : "");
612 static gpg_error_t parse_assuan_line(pwm_t *pwm)
614 gpg_error_t rc;
615 char *line;
616 size_t len;
618 rc = assuan_read_line(pwm->ctx, &line, &len);
620 if (!rc) {
621 if (line[0] == 'O' && line[1] == 'K' &&
622 (line[2] == 0 || line[2] == ' ')) {
623 pwm->state = ASYNC_DONE;
625 else if (line[0] == '#') {
627 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
628 if (pwm->status_func) {
629 rc = pwm->status_func(pwm->status_data,
630 line[1] == 0 ? line+1 : line+2);
633 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
634 (line[3] == 0 || line[3] == ' ')) {
635 line += 4;
636 rc = atoi(line);
637 pwm->state = ASYNC_DONE;
641 return gpg_err_code(rc);
644 gpg_error_t pwmd_pending_line(pwm_t *pwm)
646 if (!pwm)
647 return GPG_ERR_INV_ARG;
649 if (!pwm->ctx)
650 return GPG_ERR_INV_STATE;
652 return assuan_pending_line(pwm->ctx) ? 0 : GPG_ERR_NO_DATA;
655 static pwmd_async_t reset_async(pwm_t *pwm, int done)
657 pwm->state = ASYNC_INIT;
658 pwm->cmd = pwm->lastcmd = ASYNC_CMD_NONE;
660 #ifdef WITH_PINENTRY
661 if (pwm->nb_fd != -1) {
662 close(pwm->nb_fd);
663 pwm->nb_fd = -1;
666 if (pwm->_password) {
667 pwmd_free(pwm->_password);
668 pwm->_password = NULL;
670 #endif
671 #ifdef WITH_TCP
672 if (done && pwm->tcp_conn) {
673 _free_ssh_conn(pwm->tcp_conn);
674 pwm->tcp_conn = NULL;
676 #endif
678 return ASYNC_DONE;
682 * Used for processing status messages when not in an async command and for
683 * waiting for the result from pwmd_open_async() and pwmd_save_async().
685 static gpg_error_t _pwmd_process(pwm_t *pwm)
687 gpg_error_t rc = 0;
688 fd_set fds;
689 struct timeval tv = {0, 0};
690 int n;
692 FD_ZERO(&fds);
693 FD_SET(pwm->fd, &fds);
694 #ifdef WITH_LIBPTH
695 n = pth_select(pwm->fd+1, &fds, NULL, NULL, &tv);
696 #else
697 n = select(pwm->fd+1, &fds, NULL, NULL, &tv);
698 #endif
700 if (n == -1)
701 return gpg_error_from_syserror();
703 if (n > 0) {
704 if (FD_ISSET(pwm->fd, &fds))
705 rc = parse_assuan_line(pwm);
708 while (!rc && assuan_pending_line(pwm->ctx))
709 rc = parse_assuan_line(pwm);
711 return gpg_err_code(rc);
714 static void reset_handle(pwm_t *h)
716 h->fd = -1;
717 #ifdef WITH_PINENTRY
718 if (h->pctx)
719 _pinentry_disconnect(h);
721 h->nb_fd = -1;
722 #endif
723 h->pin_try = 0;
724 reset_async(h, 0);
727 gpg_error_t pwmd_disconnect(pwm_t *pwm)
729 if (!pwm)
730 return GPG_ERR_INV_ARG;
732 #ifdef WITH_TCP
733 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
734 #else
735 if (pwm->fd == -1)
736 #endif
737 return GPG_ERR_INV_STATE;
739 if (pwm->fd != 1)
740 disconnect(pwm);
741 #ifdef WITH_TCP
742 else
743 _ssh_disconnect(pwm);
744 #endif
746 reset_handle(pwm);
747 return 0;
750 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc, char **result)
752 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
753 fd_set fds;
754 int n;
755 struct timeval tv = {0, 0};
756 #endif
758 if (result)
759 *result = NULL;
761 if (!rc)
762 return GPG_ERR_INV_ARG;
764 *rc = 0;
766 if (!pwm) {
767 *rc = GPG_ERR_INV_ARG;
768 return ASYNC_DONE;
770 else if (!pwm->ctx) {
771 switch (pwm->cmd) {
772 default:
773 *rc = GPG_ERR_INV_STATE;
774 return ASYNC_DONE;
775 #ifdef WITH_TCP
776 case ASYNC_CMD_DNS:
777 case ASYNC_CMD_CONNECT:
778 case ASYNC_CMD_HOSTKEY:
779 break;
780 #endif
784 /* When not in a command, this will let libassuan process status messages
785 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
786 * descriptor returned by pwmd_get_fd() to determine when this should be
787 * called or call pwmd_pending_line() to determine whether a buffered line
788 * needs to be processed. */
789 if (pwm->cmd == ASYNC_CMD_NONE) {
790 *rc = _pwmd_process(pwm);
791 return ASYNC_DONE;
794 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
795 if (pwm->state == ASYNC_DONE) {
796 *rc = _pwmd_process(pwm);
797 return reset_async(pwm, 0);
800 if (pwm->state != ASYNC_PROCESS) {
801 *rc = GPG_ERR_INV_STATE;
802 return ASYNC_DONE;
805 #ifdef WITH_TCP
806 if (pwm->cmd == ASYNC_CMD_DNS) {
807 fd_set rfds, wfds;
809 if (pwm->tcp_conn->rc) {
810 *rc = pwm->tcp_conn->rc;
811 return reset_async(pwm, 1);
814 FD_ZERO(&rfds);
815 FD_ZERO(&wfds);
816 n = ares_fds(pwm->tcp_conn->chan, &rfds, &wfds);
818 /* Shouldn't happen. */
819 if (!n)
820 return pwm->state;
822 #ifdef WITH_LIBPTH
823 n = pth_select(n, &rfds, &wfds, NULL, &tv);
824 #else
825 n = select(n, &rfds, &wfds, NULL, &tv);
826 #endif
828 if (n < 0) {
829 *rc = gpg_error_from_syserror();
830 return reset_async(pwm, 1);
833 if (n > 0)
834 ares_process(pwm->tcp_conn->chan, &rfds, &wfds);
836 return pwm->state;
838 else if (pwm->cmd == ASYNC_CMD_CONNECT) {
839 if (pwm->tcp_conn->rc == GPG_ERR_EINPROGRESS) {
840 int ret;
841 socklen_t len = sizeof(int);
843 FD_ZERO(&fds);
844 FD_SET(pwm->tcp_conn->fd, &fds);
845 #ifdef WITH_LIBPTH
846 n = pth_select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
847 #else
848 n = select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
849 #endif
851 if (!n || !FD_ISSET(pwm->tcp_conn->fd, &fds))
852 return pwm->state;
853 else if (n == -1) {
854 *rc = gpg_error_from_syserror();
855 return reset_async(pwm, 1);
858 ret = getsockopt(pwm->tcp_conn->fd, SOL_SOCKET, SO_ERROR, &n, &len);
860 if (ret || n) {
861 *rc = ret ? gpg_error_from_syserror() : gpg_error_from_errno(n);
862 return reset_async(pwm, 1);
865 else if (pwm->tcp_conn->rc) {
866 *rc = pwm->tcp_conn->rc;
867 return reset_async(pwm, 1);
870 fcntl(pwm->tcp_conn->fd, F_SETFL, 0);
871 *rc = _setup_ssh_session(pwm);
873 if (!*rc) {
874 switch (pwm->tcp_conn->cmd) {
875 case ASYNC_CMD_HOSTKEY:
876 *result = pwm->result;
877 break;
878 default:
879 break;
883 return reset_async(pwm, *rc ? 1 : 0);
885 #endif
887 #ifdef WITH_PINENTRY
888 if (pwm->cmd == ASYNC_CMD_OPEN2 || pwm->cmd == ASYNC_CMD_SAVE2) {
889 int status;
891 if (pwm->nb_fd == -1) {
892 *rc = GPG_ERR_INV_STATE;
893 return reset_async(pwm, 0);
896 FD_ZERO(&fds);
897 FD_SET(pwm->nb_fd, &fds);
898 FD_SET(pwm->fd, &fds);
899 #ifdef WITH_LIBPTH
900 n = pth_select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
901 #else
902 n = select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
903 #endif
904 if (n < 0) {
905 *rc = gpg_error_from_syserror();
906 return reset_async(pwm, 0);
909 if (n > 0 && FD_ISSET(pwm->nb_fd, &fds)) {
910 pwmd_nb_status_t nb;
911 #ifdef WITH_LIBPTH
912 size_t len = pth_read(pwm->nb_fd, &nb, sizeof(nb));
913 #else
914 size_t len = read(pwm->nb_fd, &nb, sizeof(nb));
915 #endif
916 waitpid(pwm->nb_pid, &status, WNOHANG);
918 if (len != sizeof(nb)) {
919 memset(&nb, 0, sizeof(pwmd_nb_status_t));
920 *rc = gpg_error_from_syserror();
921 return reset_async(pwm, 0);
924 *rc = nb.error;
926 if (*rc)
927 return reset_async(pwm, 0);
929 /* Since the non-blocking pinentry returned a success, do a
930 * non-blocking OPEN or SAVE. */
931 pwmd_async_cmd_t c = pwm->cmd;
932 reset_async(pwm, 0);
933 pwm->_password = pwmd_strdup(nb.password);
934 memset(&nb, 0, sizeof(pwmd_nb_status_t));
935 pwm->lastcmd = c;
937 if (!pwm->_password) {
938 *rc = gpg_error_from_errno(ENOMEM);
939 return reset_async(pwm, 0);
942 if (c == ASYNC_CMD_SAVE2)
943 *rc = pwmd_save_async(pwm);
944 else
945 *rc = pwmd_open_async(pwm, pwm->filename);
947 if (*rc) {
948 reset_async(pwm, 0);
949 return ASYNC_DONE;
952 return ASYNC_PROCESS;
955 /* Fall through so status messages can be processed during the
956 * pinentry. */
958 #endif
960 if (pwm->fd < 0) {
961 *rc = GPG_ERR_INV_STATE;
962 return reset_async(pwm, 0);
965 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
966 * retries. */
967 *rc = _pwmd_process(pwm);
969 if (*rc && *rc != GPG_ERR_INV_PASSPHRASE)
970 return reset_async(pwm, 0);
972 if (pwm->cmd == ASYNC_CMD_OPEN &&
973 *rc == GPG_ERR_INV_PASSPHRASE &&
974 #ifdef WITH_TCP
975 (!pwm->tcp_conn || (pwm->tcp_conn && pwm->lastcmd == ASYNC_CMD_OPEN2)) &&
976 #endif
977 ++pwm->pin_try < pwm->pinentry_tries) {
978 if (!get_custom_passphrase(pwm, NULL))
979 goto done;
981 #ifdef WITH_PINENTRY
982 if (pwm->_password) {
983 reset_async(pwm, 0);
984 pwm->lastcmd = ASYNC_CMD_OPEN2;
985 *rc = pwmd_open_async2(pwm, pwm->filename);
987 else {
988 #endif
989 reset_async(pwm, 0);
990 pwm->lastcmd = ASYNC_CMD_OPEN;
991 *rc = pwmd_open_async(pwm, pwm->filename);
992 #ifdef WITH_PINENTRY
994 #endif
997 done:
998 if (*rc || pwm->state == ASYNC_DONE)
999 return reset_async(pwm, 0);
1001 return pwm->state;
1004 gpg_error_t _assuan_command(pwm_t *pwm, assuan_context_t ctx,
1005 char **result, const char *cmd)
1007 membuf_t data;
1008 gpg_error_t rc;
1010 if (!cmd || !*cmd)
1011 return GPG_ERR_INV_ARG;
1013 if (strlen(cmd) >= ASSUAN_LINELENGTH+1)
1014 return GPG_ERR_LINE_TOO_LONG;
1016 data.len = 0;
1017 data.buf = NULL;
1018 rc = assuan_transact(ctx, cmd, inquire_realloc_cb, &data,
1019 #ifdef WITH_QUALITY
1020 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1021 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1022 #else
1023 inquire_cb, pwm,
1024 #endif
1025 pwm->status_func, pwm->status_data);
1027 if (rc) {
1028 if (data.buf) {
1029 pwmd_free(data.buf);
1030 data.buf = NULL;
1033 else {
1034 if (data.buf) {
1035 inquire_realloc_cb(&data, "", 1);
1037 if (!result) {
1038 pwmd_free(data.buf);
1039 rc = GPG_ERR_INV_ARG;
1041 else
1042 *result = (char *)data.buf;
1046 return gpg_err_code(rc);
1049 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_cb_t fn,
1050 void *data)
1052 if (!pwm || !cmd || !fn)
1053 return GPG_ERR_INV_ARG;
1055 if (!pwm->ctx)
1056 return GPG_ERR_INV_STATE;
1058 pwm->inquire_func = fn;
1059 pwm->inquire_data = data;
1060 return _assuan_command(pwm, pwm->ctx, NULL, cmd);
1063 gpg_error_t pwmd_command_ap(pwm_t *pwm, char **result, const char *cmd,
1064 va_list ap)
1066 char *buf;
1067 size_t len;
1068 va_list ap2;
1070 if (!pwm || !cmd)
1071 return GPG_ERR_INV_ARG;
1073 if (!pwm->ctx)
1074 return GPG_ERR_INV_STATE;
1077 * C99 allows the dst pointer to be null which will calculate the length
1078 * of the would-be result and return it.
1080 va_copy(ap2, ap);
1081 len = vsnprintf(NULL, 0, cmd, ap)+1;
1082 buf = (char *)pwmd_malloc(len);
1084 if (!buf) {
1085 va_end(ap2);
1086 return gpg_error_from_errno(ENOMEM);
1089 len = vsnprintf(buf, len, cmd, ap2);
1090 va_end(ap2);
1092 if (buf[strlen(buf)-1] == '\n')
1093 buf[strlen(buf)-1] = 0;
1095 if (buf[strlen(buf)-1] == '\r')
1096 buf[strlen(buf)-1] = 0;
1098 gpg_error_t rc = _assuan_command(pwm, pwm->ctx, result, buf);
1099 pwmd_free(buf);
1100 return rc;
1103 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
1105 va_list ap;
1107 if (!pwm || !cmd)
1108 return GPG_ERR_INV_ARG;
1110 if (!pwm->ctx)
1111 return GPG_ERR_INV_STATE;
1113 if (result)
1114 *result = NULL;
1116 va_start(ap, cmd);
1117 gpg_error_t rc = pwmd_command_ap(pwm, result, cmd, ap);
1118 va_end(ap);
1119 return rc;
1122 static gpg_error_t send_pinentry_options(pwm_t *pwm)
1124 gpg_error_t rc;
1126 if (pwm->pinentry_path) {
1127 rc = pwmd_command(pwm, NULL, "OPTION PATH=%s", pwm->pinentry_path);
1129 if (rc)
1130 return rc;
1133 if (pwm->pinentry_tty) {
1134 rc = pwmd_command(pwm, NULL, "OPTION TTYNAME=%s", pwm->pinentry_tty);
1136 if (rc)
1137 return rc;
1140 if (pwm->pinentry_term) {
1141 rc = pwmd_command(pwm, NULL, "OPTION TTYTYPE=%s", pwm->pinentry_term);
1143 if (rc)
1144 return rc;
1147 if (pwm->pinentry_display) {
1148 rc = pwmd_command(pwm, NULL, "OPTION DISPLAY=%s",
1149 pwm->pinentry_display);
1151 if (rc)
1152 return rc;
1155 if (pwm->title) {
1156 rc = pwmd_command(pwm, NULL, "OPTION TITLE=%s", pwm->title);
1158 if (rc)
1159 return rc;
1162 if (pwm->desc) {
1163 rc = pwmd_command(pwm, NULL, "OPTION DESC=%s", pwm->desc);
1165 if (rc)
1166 return rc;
1169 if (pwm->prompt) {
1170 rc = pwmd_command(pwm, NULL, "OPTION PROMPT=%s", pwm->prompt);
1172 if (rc)
1173 return rc;
1176 if (pwm->lcctype) {
1177 rc = pwmd_command(pwm, NULL, "OPTION LC_CTYPE=%s", pwm->lcctype);
1179 if (rc)
1180 return rc;
1183 if (pwm->lcmessages) {
1184 rc = pwmd_command(pwm, NULL, "OPTION LC_MESSAGES=%s", pwm->lcmessages);
1186 if (rc)
1187 return rc;
1190 if (pwm->pinentry_timeout >= 0 && !pwm->pin_try) {
1191 rc = pwmd_command(pwm, NULL, "OPTION TIMEOUT=%i", pwm->pinentry_timeout);
1193 if (rc)
1194 return rc;
1197 return 0;
1200 gpg_error_t pwmd_socket_type(pwm_t *pwm, pwmd_socket_t *result)
1202 if (!pwm || !result)
1203 return GPG_ERR_INV_ARG;
1205 #ifdef WITH_TCP
1206 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
1207 #else
1208 if (pwm->fd == -1)
1209 #endif
1210 return GPG_ERR_INV_STATE;
1212 #ifdef WITH_TCP
1213 *result = pwm->tcp_conn ? PWMD_SOCKET_SSH : PWMD_SOCKET_UDS;
1214 #else
1215 *result = PWMD_SOCKET_UDS;
1216 #endif
1217 return 0;
1220 static gpg_error_t set_pinentry_retry(pwm_t *pwm)
1222 gpg_error_t rc = 0;
1224 if (pwm->pin_try == 1) {
1225 rc = pwmd_command(pwm, NULL, "OPTION TITLE=%s",
1226 N_("Invalid passphrase, please try again."));
1228 if (rc)
1229 return rc;
1231 rc = pwmd_command(pwm, NULL, "OPTION TIMEOUT=0");
1234 return rc;
1237 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result)
1239 gpg_error_t rc = GPG_ERR_NO_DATA;
1241 if (result)
1242 *result = NULL;
1243 else {
1244 if (pwm->password || pwm->passfunc)
1245 return 0;
1248 if (pwm->password) {
1249 rc = 0;
1250 *result = pwm->password;
1252 else if (pwm->passfunc)
1253 rc = pwm->passfunc(pwm->passdata, result);
1255 return rc;
1258 static gpg_error_t do_pwmd_open(pwm_t *pwm, const char *filename, int nb,
1259 int local_pinentry)
1261 char *result = NULL;
1262 char *password = NULL;
1263 char *path;
1264 gpg_error_t rc;
1266 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1267 pwm->pin_try = 0;
1269 if (!pwm || !filename || !*filename)
1270 return GPG_ERR_INV_ARG;
1272 if (!pwm->ctx)
1273 return GPG_ERR_INV_STATE;
1276 * Avoid calling pinentry if the password is cached on the server or if
1277 * this is a new file. pwmd version 2 adds a VERSION command which is
1278 * determined in _connect_finalize(). If the server is version 2,
1279 * ISCACHED will return GPG_ERR_ENOENT if it doesn't exist.
1281 #ifdef WITH_TCP
1282 /* Don't try a local filesystem lookup of the data file over a remote
1283 * connection. */
1284 if (!pwm->tcp_conn && pwm->version == PWMD_V1) {
1285 #else
1286 if (pwm->version == PWMD_V1) {
1287 #endif
1288 rc = pwmd_command(pwm, &result, "GETCONFIG data_directory");
1290 if (rc)
1291 return rc;
1293 path = pwmd_strdup_printf("%s/%s", result, filename);
1294 pwmd_free(result);
1296 if (!path)
1297 return gpg_error_from_errno(ENOMEM);
1299 if (access(path, R_OK) == -1) {
1300 if (errno == ENOENT) {
1301 pwmd_free(path);
1302 goto gotpassword;
1306 pwmd_free(path);
1309 rc = pwmd_command(pwm, &result, "ISCACHED %s", filename);
1311 /* pwmd >= 2.0 specific. This is a new file which doesn't require a
1312 * passphrase. */
1313 if (rc == GPG_ERR_ENOENT)
1314 goto gotpassword;
1316 if (rc && rc != GPG_ERR_NOT_FOUND)
1317 return rc;
1319 if (rc == GPG_ERR_NOT_FOUND) {
1320 rc = get_custom_passphrase(pwm, &password);
1322 if (rc && rc != GPG_ERR_NO_DATA)
1323 return rc;
1324 else if (rc == GPG_ERR_NO_DATA)
1325 rc = GPG_ERR_NOT_FOUND;
1326 else
1327 goto gotpassword;
1330 #ifdef WITH_PINENTRY
1331 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1332 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1333 if (!pwm->pin_try) {
1334 rc = pwmd_command(pwm, NULL, "OPTION PINENTRY=0");
1336 if (rc)
1337 return rc;
1340 rc = _pinentry_open(pwm, filename, &password, nb);
1342 /* pwmd_process() should be called if using a non-blocking local
1343 * pinentry. */
1344 if (rc || (!rc && nb))
1345 return rc;
1347 #endif
1349 gotpassword:
1350 reset_async(pwm, 0);
1352 #ifdef WITH_TCP
1353 if (!local_pinentry && !pwm->tcp_conn && !pwm->pin_try) {
1354 #else
1355 if (!local_pinentry && !pwm->pin_try) {
1356 #endif
1357 rc = send_pinentry_options(pwm);
1359 if (rc)
1360 return rc;
1363 rc = pwmd_command(pwm, NULL, "OPEN %s %s", filename,
1364 password ? password : "");
1367 * Keep the user defined password set with pwmd_setopt(). The password may
1368 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1370 if (!pwm->passfunc && password && password != pwm->password)
1371 pwmd_free(password);
1373 if (rc == GPG_ERR_INV_PASSPHRASE) {
1374 if (++pwm->pin_try < pwm->pinentry_tries) {
1375 if (!get_custom_passphrase(pwm, NULL))
1376 goto done;
1378 #ifdef WITH_PINENTRY
1379 #ifdef WITH_TCP
1380 if (pwm->tcp_conn && !local_pinentry)
1381 return rc;
1382 else if (local_pinentry)
1383 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1384 else
1385 #else
1386 if (local_pinentry)
1387 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1388 else
1389 #endif
1390 #else
1391 #ifdef WITH_TCP
1392 if (pwm->tcp_conn)
1393 return rc;
1394 else
1395 #endif
1396 #endif
1397 rc = set_pinentry_retry(pwm);
1399 if (rc)
1400 return rc;
1402 goto gotpassword;
1404 #ifdef WITH_PINENTRY
1405 else if (local_pinentry)
1406 _pinentry_disconnect(pwm);
1407 #endif
1409 done:
1410 return rc;
1412 #ifdef WITH_PINENTRY
1413 else if (rc && local_pinentry)
1414 _pinentry_disconnect(pwm);
1415 #endif
1417 if (!rc) {
1418 if (pwm->filename)
1419 pwmd_free(pwm->filename);
1421 pwm->filename = pwmd_strdup(filename);
1424 return rc;
1427 gpg_error_t pwmd_open2(pwm_t *pwm, const char *filename)
1429 #ifndef WITH_PINENTRY
1430 return GPG_ERR_NOT_IMPLEMENTED;
1431 #else
1432 return do_pwmd_open(pwm, filename, 0, 1);
1433 #endif
1436 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
1438 return do_pwmd_open(pwm, filename, 0, 0);
1441 gpg_error_t pwmd_open_async2(pwm_t *pwm, const char *filename)
1443 #ifndef WITH_PINENTRY
1444 return GPG_ERR_NOT_IMPLEMENTED;
1445 #else
1446 if (!pwm || !filename)
1447 return GPG_ERR_INV_ARG;
1449 if (!pwm->ctx)
1450 return GPG_ERR_INV_STATE;
1452 if (pwm->cmd != ASYNC_CMD_NONE)
1453 return GPG_ERR_ASS_NESTED_COMMANDS;
1455 /* Initialize a new command since this is not a pinentry retry. */
1456 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1457 pwm->pin_try = 0;
1459 pwm->cmd = ASYNC_CMD_OPEN2;
1460 pwm->state = ASYNC_PROCESS;
1461 gpg_error_t rc = do_pwmd_open(pwm, filename, 1, 1);
1463 if (rc)
1464 reset_async(pwm, 0);
1466 return rc;
1467 #endif
1470 static gpg_error_t do_pwmd_save(pwm_t *pwm, int nb, int local_pinentry)
1472 char *result = NULL;
1473 char *password = NULL;
1474 gpg_error_t rc;
1476 if (!pwm)
1477 return GPG_ERR_INV_ARG;
1479 if (!pwm->ctx)
1480 return GPG_ERR_INV_STATE;
1482 rc = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1484 if (rc == GPG_ERR_ENOENT)
1485 rc = GPG_ERR_NOT_FOUND;
1487 if (rc && rc != GPG_ERR_NOT_FOUND)
1488 return rc;
1490 if (rc == GPG_ERR_NOT_FOUND) {
1491 rc = get_custom_passphrase(pwm, &password);
1493 if (rc && rc != GPG_ERR_NO_DATA)
1494 return rc;
1495 else if (rc == GPG_ERR_NO_DATA)
1496 rc = GPG_ERR_NOT_FOUND;
1497 else
1498 goto gotpassword;
1501 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1502 #ifdef WITH_PINENTRY
1503 /* Get the password using the LOCAL pinentry. */
1504 if (nb) {
1505 int p[2];
1506 pid_t pid;
1507 pwmd_nb_status_t pw;
1509 if (pipe(p) == -1)
1510 return gpg_error_from_syserror();
1512 #ifdef WITH_LIBPTH
1513 pid = pth_fork();
1514 #else
1515 pid = fork();
1516 #endif
1518 switch (pid) {
1519 case 0:
1520 close(p[0]);
1521 pw.fd = p[0];
1522 password = NULL;
1523 pw.error = _do_save_getpin(pwm, &password);
1525 if (!pw.error) {
1526 snprintf(pw.password, sizeof(pw.password), "%s",
1527 password);
1528 pwmd_free(password);
1530 #ifdef WITH_LIBPTH
1531 pth_write(p[1], &pw, sizeof(pw));
1532 #else
1533 write(p[1], &pw, sizeof(pw));
1534 #endif
1535 memset(&pw, 0, sizeof(pw));
1536 close(p[1]);
1537 _exit(0);
1538 break;
1539 case -1:
1540 rc = gpg_error_from_syserror();
1541 close(p[0]);
1542 close(p[1]);
1543 return rc;
1544 default:
1545 break;
1548 close(p[1]);
1549 pwm->nb_fd = p[0];
1550 pwm->nb_pid = pid;
1551 return 0;
1554 rc = _do_save_getpin(pwm, &password);
1556 if (rc)
1557 return rc;
1558 #endif
1560 else
1561 pwm->state = ASYNC_DONE;
1563 gotpassword:
1564 reset_async(pwm, 0);
1566 #ifdef WITH_TCP
1567 if (!local_pinentry && !pwm->tcp_conn) {
1568 #else
1569 if (!local_pinentry) {
1570 #endif
1571 rc = send_pinentry_options(pwm);
1573 if (rc)
1574 return rc;
1577 rc = pwmd_command(pwm, NULL, "SAVE %s", password ? password : "");
1579 if (!pwm->passfunc && password && password != pwm->password)
1580 pwmd_free(password);
1582 return rc;
1585 gpg_error_t pwmd_save_async2(pwm_t *pwm)
1587 #ifndef WITH_PINENTRY
1588 return GPG_ERR_NOT_IMPLEMENTED;
1589 #else
1590 if (!pwm)
1591 return GPG_ERR_INV_ARG;
1593 if (!pwm->ctx)
1594 return GPG_ERR_INV_STATE;
1596 if (pwm->cmd != ASYNC_CMD_NONE)
1597 return GPG_ERR_ASS_NESTED_COMMANDS;
1599 pwm->cmd = ASYNC_CMD_SAVE2;
1600 pwm->state = ASYNC_PROCESS;
1601 gpg_error_t rc = do_pwmd_save(pwm, 1, 1);
1603 if (rc)
1604 reset_async(pwm, 0);
1606 return rc;
1607 #endif
1610 gpg_error_t pwmd_save2(pwm_t *pwm)
1612 #ifndef WITH_PINENTRY
1613 return GPG_ERR_NOT_IMPLEMENTED;
1614 #else
1615 return do_pwmd_save(pwm, 0, 1);
1616 #endif
1619 gpg_error_t pwmd_save(pwm_t *pwm)
1621 return do_pwmd_save(pwm, 0, 0);
1624 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1626 va_list ap;
1627 int n = va_arg(ap, int);
1628 char *arg1;
1629 gpg_error_t rc = 0;
1631 if (!pwm)
1632 return GPG_ERR_INV_ARG;
1634 va_start(ap, opt);
1636 switch (opt) {
1637 case PWMD_OPTION_STATUS_CB:
1638 pwm->status_func = va_arg(ap, pwmd_status_cb_t);
1639 break;
1640 case PWMD_OPTION_STATUS_DATA:
1641 pwm->status_data = va_arg(ap, void *);
1642 break;
1643 case PWMD_OPTION_PASSPHRASE_CB:
1644 pwm->passfunc = va_arg(ap, pwmd_passphrase_cb_t);
1645 break;
1646 case PWMD_OPTION_PASSPHRASE_DATA:
1647 pwm->passdata = va_arg(ap, void *);
1648 break;
1649 case PWMD_OPTION_PASSPHRASE:
1650 arg1 = va_arg(ap, char *);
1652 if (pwm->password)
1653 pwmd_free(pwm->password);
1655 pwm->password = pwmd_strdup(arg1);
1656 break;
1657 case PWMD_OPTION_PINENTRY_TRIES:
1658 n = va_arg(ap, int);
1660 if (n <= 0) {
1661 va_end(ap);
1662 rc = GPG_ERR_INV_VALUE;
1664 else
1665 pwm->pinentry_tries = n;
1666 break;
1667 case PWMD_OPTION_PINENTRY_TIMEOUT:
1668 n = va_arg(ap, int);
1670 if (n < 0) {
1671 va_end(ap);
1672 rc = GPG_ERR_INV_VALUE;
1674 else
1675 pwm->pinentry_timeout = n;
1676 break;
1677 case PWMD_OPTION_PINENTRY_PATH:
1678 if (pwm->pinentry_path)
1679 pwmd_free(pwm->pinentry_path);
1681 pwm->pinentry_path = _expand_homedir(va_arg(ap, char *), NULL);
1682 break;
1683 case PWMD_OPTION_PINENTRY_TTY:
1684 if (pwm->pinentry_tty)
1685 pwmd_free(pwm->pinentry_tty);
1687 pwm->pinentry_tty = pwmd_strdup(va_arg(ap, char *));
1688 break;
1689 case PWMD_OPTION_PINENTRY_DISPLAY:
1690 if (pwm->pinentry_display)
1691 pwmd_free(pwm->pinentry_display);
1693 pwm->pinentry_display = pwmd_strdup(va_arg(ap, char *));
1694 break;
1695 case PWMD_OPTION_PINENTRY_TERM:
1696 if (pwm->pinentry_term)
1697 pwmd_free(pwm->pinentry_term);
1699 pwm->pinentry_term = pwmd_strdup(va_arg(ap, char *));
1700 break;
1701 case PWMD_OPTION_PINENTRY_TITLE:
1702 if (pwm->title)
1703 pwmd_free(pwm->title);
1705 pwm->title = _percent_escape(va_arg(ap, char *));
1706 break;
1707 case PWMD_OPTION_PINENTRY_PROMPT:
1708 if (pwm->prompt)
1709 pwmd_free(pwm->prompt);
1711 pwm->prompt = _percent_escape(va_arg(ap, char *));
1712 break;
1713 case PWMD_OPTION_PINENTRY_DESC:
1714 if (pwm->desc)
1715 pwmd_free(pwm->desc);
1717 pwm->desc = _percent_escape(va_arg(ap, char *));
1718 break;
1719 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1720 if (pwm->lcctype)
1721 pwmd_free(pwm->lcctype);
1723 pwm->lcctype = pwmd_strdup(va_arg(ap, char *));
1724 break;
1725 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1726 if (pwm->lcmessages)
1727 pwmd_free(pwm->lcmessages);
1729 pwm->lcmessages = pwmd_strdup(va_arg(ap, char *));
1730 break;
1731 case PWMD_OPTION_IP_VERSION:
1732 #ifdef WITH_TCP
1733 n = va_arg(ap, int);
1735 switch (n) {
1736 case PWMD_IP_ANY:
1737 case PWMD_IPV4:
1738 case PWMD_IPV6:
1739 pwm->prot = n;
1740 break;
1741 default:
1742 rc = GPG_ERR_INV_VALUE;
1743 break;
1746 va_end(ap);
1747 #else
1748 rc = GPG_ERR_NOT_IMPLEMENTED;
1749 #endif
1750 break;
1751 default:
1752 rc = GPG_ERR_UNKNOWN_OPTION;
1753 break;
1756 va_end(ap);
1757 return rc;
1760 gpg_error_t pwmd_get_fds(pwm_t *pwm, pwmd_fd_t *fds, int *n_fds)
1762 int in_total;
1763 int fd = 0;
1764 #ifdef WITH_TCP
1765 int afds[ARES_GETSOCK_MAXNUM];
1766 int got_sock = 0;
1767 int n, i;
1768 #endif
1770 if (!pwm || !fds || !n_fds || *n_fds <= 0)
1771 return GPG_ERR_INV_ARG;
1773 in_total = *n_fds;
1774 #ifdef WITH_TCP
1775 memset(afds, 0, sizeof(int)*ARES_GETSOCK_MAXNUM);
1776 #endif
1777 memset(fds, 0, sizeof(pwmd_fd_t)*in_total);
1778 *n_fds = 0;
1780 switch (pwm->cmd) {
1781 default:
1782 case ASYNC_CMD_NONE:
1783 case ASYNC_CMD_OPEN:
1784 case ASYNC_CMD_SAVE:
1785 #ifdef WITH_PINENTRY
1786 async1:
1787 #endif
1788 if (pwm->fd == -1)
1789 return GPG_ERR_INV_STATE;
1791 (*n_fds)++;
1792 fds[fd].fd = pwm->fd;
1793 fds[fd++].flags = PWMD_FD_READABLE;
1794 return 0;
1795 #ifdef WITH_PINENTRY
1796 case ASYNC_CMD_OPEN2:
1797 case ASYNC_CMD_SAVE2:
1798 /* The command has already completed (cached or new). */
1799 if (pwm->state == ASYNC_DONE)
1800 return 0;
1802 if (pwm->nb_fd == -1)
1803 return GPG_ERR_INV_STATE;
1805 (*n_fds)++;
1806 fds[fd].fd = pwm->nb_fd;
1807 fds[fd++].flags = PWMD_FD_READABLE;
1808 goto async1;
1809 #endif
1810 #ifdef WITH_TCP
1811 case ASYNC_CMD_DNS:
1812 if (!pwm->tcp_conn || !pwm->tcp_conn->chan)
1813 return GPG_ERR_INV_STATE;
1815 n = ares_getsock(pwm->tcp_conn->chan, afds, ARES_GETSOCK_MAXNUM);
1817 for (i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
1818 got_sock = 0;
1820 if (fd > in_total) {
1821 *n_fds = fd;
1822 return GPG_ERR_ERANGE;
1825 if (ARES_GETSOCK_READABLE(n, i)) {
1826 got_sock++;
1827 fds[fd].flags |= PWMD_FD_READABLE;
1830 if (ARES_GETSOCK_WRITABLE(n, i)) {
1831 got_sock++;
1832 fds[fd].flags |= PWMD_FD_WRITABLE;
1835 if (got_sock)
1836 fds[fd++].fd = afds[i];
1839 *n_fds = fd;
1840 return 0;
1841 case ASYNC_CMD_CONNECT:
1842 case ASYNC_CMD_HOSTKEY:
1843 if (!pwm->tcp_conn || pwm->tcp_conn->fd == -1)
1844 return GPG_ERR_INV_STATE;
1846 (*n_fds)++;
1847 fds[fd].fd = pwm->tcp_conn->fd;
1848 fds[fd++].flags = PWMD_FD_READABLE;
1849 return 0;
1850 #endif
1853 return GPG_ERR_INV_STATE;
1856 pwm_t *pwmd_new(const char *name)
1858 pwm_t *h = pwmd_calloc(1, sizeof(pwm_t));
1860 if (!h)
1861 return NULL;
1863 if (name) {
1864 h->name = pwmd_strdup(name);
1866 if (!h->name) {
1867 pwmd_free(h);
1868 return NULL;
1872 reset_handle(h);
1873 h->pinentry_timeout = -30;
1874 h->pinentry_tries = 3;
1875 #ifdef WITH_TCP
1876 h->prot = PWMD_IP_ANY;
1877 #endif
1879 if (ttyname(STDOUT_FILENO)) {
1880 char buf[256];
1882 ttyname_r(STDOUT_FILENO, buf, sizeof(buf));
1883 h->pinentry_tty = pwmd_strdup(buf);
1885 if (!h->pinentry_tty)
1886 goto fail;
1889 if (getenv("TERM") && h->pinentry_tty) {
1890 h->pinentry_term = pwmd_strdup(getenv("TERM"));
1892 if (!h->pinentry_term)
1893 goto fail;
1896 if (getenv("DISPLAY")) {
1897 h->pinentry_display = pwmd_strdup(getenv("DISPLAY"));
1899 if (!h->pinentry_display)
1900 goto fail;
1903 return h;
1905 fail:
1906 pwmd_close(h);
1907 return NULL;
1910 void pwmd_free(void *ptr)
1912 _xfree(ptr);
1915 void *pwmd_malloc(size_t size)
1917 return _xmalloc(size);
1920 void *pwmd_calloc(size_t nmemb, size_t size)
1922 return _xcalloc(nmemb, size);
1925 void *pwmd_realloc(void *ptr, size_t size)
1927 return _xrealloc(ptr, size);
1930 char *pwmd_strdup(const char *str)
1932 return _xstrdup(str);
1935 char *pwmd_strdup_printf(const char *fmt, ...)
1937 va_list ap, ap2;
1938 int len;
1939 char *buf;
1941 if (!fmt)
1942 return NULL;
1944 va_start(ap, fmt);
1945 va_copy(ap2, ap);
1946 len = vsnprintf(NULL, 0, fmt, ap);
1947 va_end(ap);
1948 buf = pwmd_malloc(++len);
1950 if (buf)
1951 vsnprintf(buf, len, fmt, ap2);
1953 va_end(ap2);
1954 return buf;
1957 gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result,
1958 pwmd_pinentry_t which)
1960 #ifndef WITH_PINENTRY
1961 return GPG_ERR_NOT_IMPLEMENTED;
1962 #else
1963 return _pwmd_getpin(pwm, filename, result, which);
1964 #endif