Use pth_fdmode() where needed.
[libpwmd.git] / src / libpwmd.c
blobe9d24f4e6f4d9ca28d7ed0d16ac896d1b1d1fd71
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 #ifdef WITH_PINENTRY
360 if (pwm->pctx)
361 _pinentry_disconnect(pwm);
362 #endif
364 pwmd_free(pwm);
367 gpg_error_t pwmd_ssh_connect_async(pwm_t *pwm, const char *host, int port,
368 const char *identity, const char *user, const char *known_hosts)
370 #ifndef WITH_TCP
371 return GPG_ERR_NOT_IMPLEMENTED;
372 #else
373 return _do_pwmd_ssh_connect_async(pwm, host, port, identity, user,
374 known_hosts, ASYNC_CMD_CONNECT);
375 #endif
378 gpg_error_t pwmd_ssh_connect(pwm_t *pwm, const char *host, int port,
379 const char *identity, const char *user, const char *known_hosts)
381 #ifndef WITH_TCP
382 return GPG_ERR_NOT_IMPLEMENTED;
383 #else
384 return _do_pwmd_ssh_connect(pwm, host, port, identity, user, known_hosts, 0);
385 #endif
388 gpg_error_t pwmd_get_hostkey(pwm_t *pwm, const char *host, int port,
389 char **result)
391 #ifndef WITH_TCP
392 return GPG_ERR_NOT_IMPLEMENTED;
393 #else
394 char *hostkey;
395 gpg_error_t rc;
397 rc = _do_pwmd_ssh_connect(pwm, host, port, NULL, NULL, NULL, 1);
399 if (rc)
400 return rc;
402 hostkey = pwmd_strdup(pwm->tcp_conn->hostkey);
404 if (!hostkey)
405 rc = gpg_error_from_errno(ENOMEM);
407 *result = hostkey;
408 return rc;
409 #endif
412 gpg_error_t pwmd_get_hostkey_async(pwm_t *pwm, const char *host, int port)
414 #ifndef WITH_TCP
415 return GPG_ERR_NOT_IMPLEMENTED;
416 #else
417 return _do_pwmd_ssh_connect_async(pwm, host, port, NULL, NULL, NULL,
418 ASYNC_CMD_HOSTKEY);
419 #endif
422 static int inquire_realloc_cb(void *data, const void *buffer, size_t len)
424 membuf_t *mem = (membuf_t *)data;
425 void *p;
427 if (!buffer)
428 return 0;
430 if ((p = pwmd_realloc(mem->buf, mem->len + len)) == NULL)
431 return gpg_error_from_errno(ENOMEM);
433 mem->buf = p;
434 memcpy((char *)mem->buf + mem->len, buffer, len);
435 mem->len += len;
436 return 0;
439 static int inquire_cb(void *data, const char *keyword)
441 pwm_t *pwm = (pwm_t *)data;
442 gpg_error_t rc = 0;
443 #ifdef WITH_LIBPTH
444 int flags = pth_fdmode(pwm->fd, PTH_FDMODE_POLL);
445 #else
446 int flags = fcntl(pwm->fd, F_GETFL);
447 #endif
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;
467 arc = assuan_send_data(pwm->ctx, result, len);
468 arc = gpg_err_code(arc);
470 if (rc == GPG_ERR_EOF) {
471 rc = arc;
472 break;
475 rc = arc;
477 else if (rc)
478 break;
480 if (!rc) {
481 /* Set to non-blocking so _pwmd_process() can return. */
482 #ifdef WITH_LIBPTH
483 pth_fdmode(pwm->fd, PTH_FDMODE_NONBLOCK);
484 #else
485 fcntl(pwm->fd, F_SETFL, O_NONBLOCK);
486 #endif
487 rc = _pwmd_process(pwm);
488 #ifdef WITH_LIBPTH
489 pth_fdmode(pwm->fd, flags);
490 #else
491 fcntl(pwm->fd, F_SETFL, flags);
492 #endif
496 #ifdef WITH_LIBPTH
497 pth_fdmode(pwm->fd, flags);
498 #else
499 fcntl(pwm->fd, F_SETFL, flags);
500 #endif
501 return gpg_err_code(rc);
504 static gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, ...)
506 char *buf;
507 gpg_error_t rc;
508 va_list ap;
509 int len;
511 if (pwm->state == ASYNC_DONE)
512 pwm->state = ASYNC_INIT;
514 if (pwm->state != ASYNC_INIT)
515 return GPG_ERR_INV_STATE;
517 buf = pwmd_malloc(ASSUAN_LINELENGTH+1);
519 if (!buf)
520 return gpg_error_from_errno(ENOMEM);
522 va_start(ap, cmd);
523 len = vsnprintf(buf, ASSUAN_LINELENGTH+1, cmd, ap);
524 va_end(ap);
526 if (len >= ASSUAN_LINELENGTH+1) {
527 pwmd_free(buf);
528 return GPG_ERR_LINE_TOO_LONG;
531 rc = assuan_write_line(pwm->ctx, buf);
532 pwmd_free(buf);
534 if (!rc)
535 pwm->state = ASYNC_PROCESS;
537 return gpg_err_code(rc);
540 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
542 char *p = NULL;
543 const char *f = NULL;
544 gpg_error_t rc;
546 if (!pwm || !filename)
547 return GPG_ERR_INV_ARG;
549 if (!pwm->ctx)
550 return GPG_ERR_INV_STATE;
552 if (pwm->cmd != ASYNC_CMD_NONE)
553 return GPG_ERR_ASS_NESTED_COMMANDS;
555 if (pwm->lastcmd == ASYNC_CMD_NONE) {
556 pwm->pin_try = 0;
558 if (pwm->filename)
559 pwmd_free(pwm->filename);
561 pwm->filename = pwmd_strdup(filename);
563 if (!pwm->filename)
564 return gpg_error_from_errno(ENOMEM);
566 gpg_error_t rc = send_pinentry_options(pwm);
568 if (rc)
569 return rc;
571 rc = get_custom_passphrase(pwm, &p);
573 if (rc && rc != GPG_ERR_NO_DATA)
574 return rc;
576 f = filename;
578 #ifdef WITH_PINENTRY
579 else if (pwm->lastcmd == ASYNC_CMD_OPEN2) {
580 p = pwm->_password;
581 f = pwm->filename;
583 #endif
584 else if (pwm->lastcmd == ASYNC_CMD_OPEN) {
585 rc = set_pinentry_retry(pwm);
587 if (rc)
588 return rc;
590 p = pwm->password;
591 f = filename;
593 else
594 return GPG_ERR_INV_STATE;
596 pwm->cmd = ASYNC_CMD_OPEN;
597 return do_nb_command(pwm, "OPEN %s %s", f, p ? p : "");
600 gpg_error_t pwmd_save_async(pwm_t *pwm)
602 char *p = NULL;
604 if (!pwm)
605 return GPG_ERR_INV_ARG;
607 if (!pwm->ctx)
608 return GPG_ERR_INV_STATE;
610 if (pwm->cmd != ASYNC_CMD_NONE)
611 return GPG_ERR_ASS_NESTED_COMMANDS;
613 if (pwm->lastcmd != ASYNC_CMD_SAVE2) {
614 gpg_error_t rc = send_pinentry_options(pwm);
616 if (rc)
617 return rc;
619 rc = get_custom_passphrase(pwm, &p);
621 if (rc && rc != GPG_ERR_NO_DATA)
622 return rc;
624 #ifdef WITH_PINENTRY
625 else
626 p = pwm->_password;
627 #endif
629 pwm->cmd = ASYNC_CMD_SAVE;
630 return do_nb_command(pwm, "SAVE %s", p ? p : "");
633 static gpg_error_t parse_assuan_line(pwm_t *pwm)
635 gpg_error_t rc;
636 char *line;
637 size_t len;
639 rc = assuan_read_line(pwm->ctx, &line, &len);
641 if (!rc) {
642 if (line[0] == 'O' && line[1] == 'K' &&
643 (line[2] == 0 || line[2] == ' ')) {
644 pwm->state = ASYNC_DONE;
646 else if (line[0] == '#') {
648 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
649 if (pwm->status_func) {
650 rc = pwm->status_func(pwm->status_data,
651 line[1] == 0 ? line+1 : line+2);
654 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
655 (line[3] == 0 || line[3] == ' ')) {
656 line += 4;
657 rc = atoi(line);
658 pwm->state = ASYNC_DONE;
662 return gpg_err_code(rc);
665 gpg_error_t pwmd_pending_line(pwm_t *pwm)
667 if (!pwm)
668 return GPG_ERR_INV_ARG;
670 if (!pwm->ctx)
671 return GPG_ERR_INV_STATE;
673 return assuan_pending_line(pwm->ctx) ? 0 : GPG_ERR_NO_DATA;
676 static pwmd_async_t reset_async(pwm_t *pwm, int done)
678 pwm->state = ASYNC_INIT;
679 pwm->cmd = pwm->lastcmd = ASYNC_CMD_NONE;
681 #ifdef WITH_PINENTRY
682 if (pwm->nb_fd != -1) {
683 close(pwm->nb_fd);
684 pwm->nb_fd = -1;
687 if (pwm->_password) {
688 pwmd_free(pwm->_password);
689 pwm->_password = NULL;
691 #endif
692 #ifdef WITH_TCP
693 if (done && pwm->tcp_conn) {
694 _free_ssh_conn(pwm->tcp_conn);
695 pwm->tcp_conn = NULL;
697 #endif
699 return ASYNC_DONE;
703 * Used for processing status messages when not in an async command and for
704 * waiting for the result from pwmd_open_async() and pwmd_save_async().
706 static gpg_error_t _pwmd_process(pwm_t *pwm)
708 gpg_error_t rc = 0;
709 fd_set fds;
710 struct timeval tv = {0, 0};
711 int n;
713 FD_ZERO(&fds);
714 FD_SET(pwm->fd, &fds);
715 #ifdef WITH_LIBPTH
716 n = pth_select(pwm->fd+1, &fds, NULL, NULL, &tv);
717 #else
718 n = select(pwm->fd+1, &fds, NULL, NULL, &tv);
719 #endif
721 if (n == -1)
722 return gpg_error_from_syserror();
724 if (n > 0) {
725 if (FD_ISSET(pwm->fd, &fds))
726 rc = parse_assuan_line(pwm);
729 while (!rc && assuan_pending_line(pwm->ctx))
730 rc = parse_assuan_line(pwm);
732 return gpg_err_code(rc);
735 static void reset_handle(pwm_t *h)
737 h->fd = -1;
738 #ifdef WITH_PINENTRY
739 if (h->pctx)
740 _pinentry_disconnect(h);
742 h->nb_fd = -1;
743 #endif
744 h->pin_try = 0;
745 reset_async(h, 0);
748 gpg_error_t pwmd_disconnect(pwm_t *pwm)
750 if (!pwm)
751 return GPG_ERR_INV_ARG;
753 #ifdef WITH_TCP
754 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
755 #else
756 if (pwm->fd == -1)
757 #endif
758 return GPG_ERR_INV_STATE;
760 if (pwm->fd != 1)
761 disconnect(pwm);
762 #ifdef WITH_TCP
763 else
764 _ssh_disconnect(pwm);
765 #endif
767 reset_handle(pwm);
768 return 0;
771 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc, char **result)
773 #if defined(WITH_PINENTRY) || defined(WITH_TCP)
774 fd_set fds;
775 int n;
776 struct timeval tv = {0, 0};
777 #endif
779 if (result)
780 *result = NULL;
782 if (!rc)
783 return GPG_ERR_INV_ARG;
785 *rc = 0;
787 if (!pwm) {
788 *rc = GPG_ERR_INV_ARG;
789 return ASYNC_DONE;
791 else if (!pwm->ctx) {
792 switch (pwm->cmd) {
793 default:
794 *rc = GPG_ERR_INV_STATE;
795 return ASYNC_DONE;
796 #ifdef WITH_TCP
797 case ASYNC_CMD_DNS:
798 case ASYNC_CMD_CONNECT:
799 case ASYNC_CMD_HOSTKEY:
800 break;
801 #endif
805 /* When not in a command, this will let libassuan process status messages
806 * by calling PWMD_OPTION_STATUS_FUNC. The client can poll the file
807 * descriptor returned by pwmd_get_fd() to determine when this should be
808 * called or call pwmd_pending_line() to determine whether a buffered line
809 * needs to be processed. */
810 if (pwm->cmd == ASYNC_CMD_NONE) {
811 *rc = _pwmd_process(pwm);
812 return ASYNC_DONE;
815 /* Fixes pwmd_open/save_async2() when there is a cached or new file. */
816 if (pwm->state == ASYNC_DONE) {
817 *rc = _pwmd_process(pwm);
818 return reset_async(pwm, 0);
821 if (pwm->state != ASYNC_PROCESS) {
822 *rc = GPG_ERR_INV_STATE;
823 return ASYNC_DONE;
826 #ifdef WITH_TCP
827 if (pwm->cmd == ASYNC_CMD_DNS) {
828 fd_set rfds, wfds;
830 if (pwm->tcp_conn->rc) {
831 *rc = pwm->tcp_conn->rc;
832 return reset_async(pwm, 1);
835 FD_ZERO(&rfds);
836 FD_ZERO(&wfds);
837 n = ares_fds(pwm->tcp_conn->chan, &rfds, &wfds);
839 /* Shouldn't happen. */
840 if (!n)
841 return pwm->state;
843 #ifdef WITH_LIBPTH
844 n = pth_select(n, &rfds, &wfds, NULL, &tv);
845 #else
846 n = select(n, &rfds, &wfds, NULL, &tv);
847 #endif
849 if (n < 0) {
850 *rc = gpg_error_from_syserror();
851 return reset_async(pwm, 1);
854 if (n > 0)
855 ares_process(pwm->tcp_conn->chan, &rfds, &wfds);
857 return pwm->state;
859 else if (pwm->cmd == ASYNC_CMD_CONNECT) {
860 if (pwm->tcp_conn->rc == GPG_ERR_EINPROGRESS) {
861 int ret;
862 socklen_t len = sizeof(int);
864 FD_ZERO(&fds);
865 FD_SET(pwm->tcp_conn->fd, &fds);
866 #ifdef WITH_LIBPTH
867 n = pth_select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
868 #else
869 n = select(pwm->tcp_conn->fd+1, NULL, &fds, NULL, &tv);
870 #endif
872 if (!n || !FD_ISSET(pwm->tcp_conn->fd, &fds))
873 return pwm->state;
874 else if (n == -1) {
875 *rc = gpg_error_from_syserror();
876 return reset_async(pwm, 1);
879 ret = getsockopt(pwm->tcp_conn->fd, SOL_SOCKET, SO_ERROR, &n, &len);
881 if (ret || n) {
882 *rc = ret ? gpg_error_from_syserror() : gpg_error_from_errno(n);
883 return reset_async(pwm, 1);
886 else if (pwm->tcp_conn->rc) {
887 *rc = pwm->tcp_conn->rc;
888 return reset_async(pwm, 1);
891 fcntl(pwm->tcp_conn->fd, F_SETFL, 0);
892 *rc = _setup_ssh_session(pwm);
894 if (!*rc) {
895 switch (pwm->tcp_conn->cmd) {
896 case ASYNC_CMD_HOSTKEY:
897 *result = pwm->result;
898 break;
899 default:
900 break;
904 return reset_async(pwm, *rc ? 1 : 0);
906 #endif
908 #ifdef WITH_PINENTRY
909 if (pwm->cmd == ASYNC_CMD_OPEN2 || pwm->cmd == ASYNC_CMD_SAVE2) {
910 int status;
912 if (pwm->nb_fd == -1) {
913 *rc = GPG_ERR_INV_STATE;
914 return reset_async(pwm, 0);
917 FD_ZERO(&fds);
918 FD_SET(pwm->nb_fd, &fds);
919 FD_SET(pwm->fd, &fds);
920 #ifdef WITH_LIBPTH
921 n = pth_select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
922 #else
923 n = select(pwm->nb_fd+1, &fds, NULL, NULL, &tv);
924 #endif
925 if (n < 0) {
926 *rc = gpg_error_from_syserror();
927 return reset_async(pwm, 0);
930 if (n > 0 && FD_ISSET(pwm->nb_fd, &fds)) {
931 pwmd_nb_status_t nb;
932 #ifdef WITH_LIBPTH
933 size_t len = pth_read(pwm->nb_fd, &nb, sizeof(nb));
934 #else
935 size_t len = read(pwm->nb_fd, &nb, sizeof(nb));
936 #endif
937 waitpid(pwm->nb_pid, &status, WNOHANG);
939 if (len != sizeof(nb)) {
940 memset(&nb, 0, sizeof(pwmd_nb_status_t));
941 *rc = gpg_error_from_syserror();
942 return reset_async(pwm, 0);
945 *rc = nb.error;
947 if (*rc)
948 return reset_async(pwm, 0);
950 /* Since the non-blocking pinentry returned a success, do a
951 * non-blocking OPEN or SAVE. */
952 pwmd_async_cmd_t c = pwm->cmd;
953 reset_async(pwm, 0);
954 pwm->_password = pwmd_strdup(nb.password);
955 memset(&nb, 0, sizeof(pwmd_nb_status_t));
956 pwm->lastcmd = c;
958 if (!pwm->_password) {
959 *rc = gpg_error_from_errno(ENOMEM);
960 return reset_async(pwm, 0);
963 if (c == ASYNC_CMD_SAVE2)
964 *rc = pwmd_save_async(pwm);
965 else
966 *rc = pwmd_open_async(pwm, pwm->filename);
968 if (*rc) {
969 reset_async(pwm, 0);
970 return ASYNC_DONE;
973 return ASYNC_PROCESS;
976 /* Fall through so status messages can be processed during the
977 * pinentry. */
979 #endif
981 if (pwm->fd < 0) {
982 *rc = GPG_ERR_INV_STATE;
983 return reset_async(pwm, 0);
986 /* This is for pwmd_open_async() and pwmd_save_async(). For pinentry
987 * retries. */
988 *rc = _pwmd_process(pwm);
990 if (*rc && *rc != GPG_ERR_INV_PASSPHRASE)
991 return reset_async(pwm, 0);
993 if (pwm->cmd == ASYNC_CMD_OPEN &&
994 *rc == GPG_ERR_INV_PASSPHRASE &&
995 #ifdef WITH_TCP
996 (!pwm->tcp_conn || (pwm->tcp_conn && pwm->lastcmd == ASYNC_CMD_OPEN2)) &&
997 #endif
998 ++pwm->pin_try < pwm->pinentry_tries) {
999 if (!get_custom_passphrase(pwm, NULL))
1000 goto done;
1002 #ifdef WITH_PINENTRY
1003 if (pwm->_password) {
1004 reset_async(pwm, 0);
1005 pwm->lastcmd = ASYNC_CMD_OPEN2;
1006 *rc = pwmd_open_async2(pwm, pwm->filename);
1008 else {
1009 #endif
1010 reset_async(pwm, 0);
1011 pwm->lastcmd = ASYNC_CMD_OPEN;
1012 *rc = pwmd_open_async(pwm, pwm->filename);
1013 #ifdef WITH_PINENTRY
1015 #endif
1018 done:
1019 if (*rc || pwm->state == ASYNC_DONE)
1020 return reset_async(pwm, 0);
1022 return pwm->state;
1025 gpg_error_t _assuan_command(pwm_t *pwm, assuan_context_t ctx,
1026 char **result, const char *cmd)
1028 membuf_t data;
1029 gpg_error_t rc;
1031 if (!cmd || !*cmd)
1032 return GPG_ERR_INV_ARG;
1034 if (strlen(cmd) >= ASSUAN_LINELENGTH+1)
1035 return GPG_ERR_LINE_TOO_LONG;
1037 data.len = 0;
1038 data.buf = NULL;
1039 rc = assuan_transact(ctx, cmd, inquire_realloc_cb, &data,
1040 #ifdef WITH_QUALITY
1041 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1042 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1043 #else
1044 inquire_cb, pwm,
1045 #endif
1046 pwm->status_func, pwm->status_data);
1048 if (rc) {
1049 if (data.buf) {
1050 pwmd_free(data.buf);
1051 data.buf = NULL;
1054 else {
1055 if (data.buf) {
1056 inquire_realloc_cb(&data, "", 1);
1058 if (!result) {
1059 pwmd_free(data.buf);
1060 rc = GPG_ERR_INV_ARG;
1062 else
1063 *result = (char *)data.buf;
1067 return gpg_err_code(rc);
1070 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_cb_t fn,
1071 void *data)
1073 if (!pwm || !cmd || !fn)
1074 return GPG_ERR_INV_ARG;
1076 if (!pwm->ctx)
1077 return GPG_ERR_INV_STATE;
1079 pwm->inquire_func = fn;
1080 pwm->inquire_data = data;
1081 return _assuan_command(pwm, pwm->ctx, NULL, cmd);
1084 gpg_error_t pwmd_command_ap(pwm_t *pwm, char **result, const char *cmd,
1085 va_list ap)
1087 char *buf;
1088 size_t len;
1089 va_list ap2;
1091 if (!pwm || !cmd)
1092 return GPG_ERR_INV_ARG;
1094 if (!pwm->ctx)
1095 return GPG_ERR_INV_STATE;
1098 * C99 allows the dst pointer to be null which will calculate the length
1099 * of the would-be result and return it.
1101 va_copy(ap2, ap);
1102 len = vsnprintf(NULL, 0, cmd, ap)+1;
1103 buf = (char *)pwmd_malloc(len);
1105 if (!buf) {
1106 va_end(ap2);
1107 return gpg_error_from_errno(ENOMEM);
1110 len = vsnprintf(buf, len, cmd, ap2);
1111 va_end(ap2);
1113 if (buf[strlen(buf)-1] == '\n')
1114 buf[strlen(buf)-1] = 0;
1116 if (buf[strlen(buf)-1] == '\r')
1117 buf[strlen(buf)-1] = 0;
1119 gpg_error_t rc = _assuan_command(pwm, pwm->ctx, result, buf);
1120 pwmd_free(buf);
1121 return rc;
1124 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
1126 va_list ap;
1128 if (!pwm || !cmd)
1129 return GPG_ERR_INV_ARG;
1131 if (!pwm->ctx)
1132 return GPG_ERR_INV_STATE;
1134 if (result)
1135 *result = NULL;
1137 va_start(ap, cmd);
1138 gpg_error_t rc = pwmd_command_ap(pwm, result, cmd, ap);
1139 va_end(ap);
1140 return rc;
1143 static gpg_error_t send_pinentry_options(pwm_t *pwm)
1145 gpg_error_t rc;
1147 if (pwm->pinentry_path) {
1148 rc = pwmd_command(pwm, NULL, "OPTION PATH=%s", pwm->pinentry_path);
1150 if (rc)
1151 return rc;
1154 if (pwm->pinentry_tty) {
1155 rc = pwmd_command(pwm, NULL, "OPTION TTYNAME=%s", pwm->pinentry_tty);
1157 if (rc)
1158 return rc;
1161 if (pwm->pinentry_term) {
1162 rc = pwmd_command(pwm, NULL, "OPTION TTYTYPE=%s", pwm->pinentry_term);
1164 if (rc)
1165 return rc;
1168 if (pwm->pinentry_display) {
1169 rc = pwmd_command(pwm, NULL, "OPTION DISPLAY=%s",
1170 pwm->pinentry_display);
1172 if (rc)
1173 return rc;
1176 if (pwm->title) {
1177 rc = pwmd_command(pwm, NULL, "OPTION TITLE=%s", pwm->title);
1179 if (rc)
1180 return rc;
1183 if (pwm->desc) {
1184 rc = pwmd_command(pwm, NULL, "OPTION DESC=%s", pwm->desc);
1186 if (rc)
1187 return rc;
1190 if (pwm->prompt) {
1191 rc = pwmd_command(pwm, NULL, "OPTION PROMPT=%s", pwm->prompt);
1193 if (rc)
1194 return rc;
1197 if (pwm->lcctype) {
1198 rc = pwmd_command(pwm, NULL, "OPTION LC_CTYPE=%s", pwm->lcctype);
1200 if (rc)
1201 return rc;
1204 if (pwm->lcmessages) {
1205 rc = pwmd_command(pwm, NULL, "OPTION LC_MESSAGES=%s", pwm->lcmessages);
1207 if (rc)
1208 return rc;
1211 if (pwm->pinentry_timeout >= 0 && !pwm->pin_try) {
1212 rc = pwmd_command(pwm, NULL, "OPTION TIMEOUT=%i", pwm->pinentry_timeout);
1214 if (rc)
1215 return rc;
1218 return 0;
1221 gpg_error_t pwmd_socket_type(pwm_t *pwm, pwmd_socket_t *result)
1223 if (!pwm || !result)
1224 return GPG_ERR_INV_ARG;
1226 #ifdef WITH_TCP
1227 if (pwm->fd == -1 && pwm->tcp_conn && pwm->tcp_conn->fd == -1)
1228 #else
1229 if (pwm->fd == -1)
1230 #endif
1231 return GPG_ERR_INV_STATE;
1233 #ifdef WITH_TCP
1234 *result = pwm->tcp_conn ? PWMD_SOCKET_SSH : PWMD_SOCKET_UDS;
1235 #else
1236 *result = PWMD_SOCKET_UDS;
1237 #endif
1238 return 0;
1241 static gpg_error_t set_pinentry_retry(pwm_t *pwm)
1243 gpg_error_t rc = 0;
1245 if (pwm->pin_try == 1) {
1246 rc = pwmd_command(pwm, NULL, "OPTION TITLE=%s",
1247 N_("Invalid passphrase, please try again."));
1249 if (rc)
1250 return rc;
1252 rc = pwmd_command(pwm, NULL, "OPTION TIMEOUT=0");
1255 return rc;
1258 static gpg_error_t get_custom_passphrase(pwm_t *pwm, char **result)
1260 gpg_error_t rc = GPG_ERR_NO_DATA;
1262 if (result)
1263 *result = NULL;
1264 else {
1265 if (pwm->password || pwm->passfunc)
1266 return 0;
1269 if (pwm->password) {
1270 rc = 0;
1271 *result = pwm->password;
1273 else if (pwm->passfunc)
1274 rc = pwm->passfunc(pwm->passdata, result);
1276 return rc;
1279 static gpg_error_t do_pwmd_open(pwm_t *pwm, const char *filename, int nb,
1280 int local_pinentry)
1282 char *result = NULL;
1283 char *password = NULL;
1284 char *path;
1285 gpg_error_t rc;
1287 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1288 pwm->pin_try = 0;
1290 if (!pwm || !filename || !*filename)
1291 return GPG_ERR_INV_ARG;
1293 if (!pwm->ctx)
1294 return GPG_ERR_INV_STATE;
1297 * Avoid calling pinentry if the password is cached on the server or if
1298 * this is a new file. pwmd version 2 adds a VERSION command which is
1299 * determined in _connect_finalize(). If the server is version 2,
1300 * ISCACHED will return GPG_ERR_ENOENT if it doesn't exist.
1302 #ifdef WITH_TCP
1303 /* Don't try a local filesystem lookup of the data file over a remote
1304 * connection. */
1305 if (!pwm->tcp_conn && pwm->version == PWMD_V1) {
1306 #else
1307 if (pwm->version == PWMD_V1) {
1308 #endif
1309 rc = pwmd_command(pwm, &result, "GETCONFIG data_directory");
1311 if (rc)
1312 return rc;
1314 path = pwmd_strdup_printf("%s/%s", result, filename);
1315 pwmd_free(result);
1317 if (!path)
1318 return gpg_error_from_errno(ENOMEM);
1320 if (access(path, R_OK) == -1) {
1321 if (errno == ENOENT) {
1322 pwmd_free(path);
1323 goto gotpassword;
1327 pwmd_free(path);
1330 rc = pwmd_command(pwm, &result, "ISCACHED %s", filename);
1332 /* pwmd >= 2.0 specific. This is a new file which doesn't require a
1333 * passphrase. */
1334 if (rc == GPG_ERR_ENOENT)
1335 goto gotpassword;
1337 if (rc && rc != GPG_ERR_NOT_FOUND)
1338 return rc;
1340 if (rc == GPG_ERR_NOT_FOUND) {
1341 rc = get_custom_passphrase(pwm, &password);
1343 if (rc && rc != GPG_ERR_NO_DATA)
1344 return rc;
1345 else if (rc == GPG_ERR_NO_DATA)
1346 rc = GPG_ERR_NOT_FOUND;
1347 else
1348 goto gotpassword;
1351 #ifdef WITH_PINENTRY
1352 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1353 /* Prevent pwmd from using it's pinentry if the passphrase fails. */
1354 if (!pwm->pin_try) {
1355 rc = pwmd_command(pwm, NULL, "OPTION PINENTRY=0");
1357 if (rc)
1358 return rc;
1361 rc = _pinentry_open(pwm, filename, &password, nb);
1363 /* pwmd_process() should be called if using a non-blocking local
1364 * pinentry. */
1365 if (rc || (!rc && nb))
1366 return rc;
1368 #endif
1370 gotpassword:
1371 reset_async(pwm, 0);
1373 #ifdef WITH_TCP
1374 if (!local_pinentry && !pwm->tcp_conn && !pwm->pin_try) {
1375 #else
1376 if (!local_pinentry && !pwm->pin_try) {
1377 #endif
1378 rc = send_pinentry_options(pwm);
1380 if (rc)
1381 return rc;
1384 rc = pwmd_command(pwm, NULL, "OPEN %s %s", filename,
1385 password ? password : "");
1388 * Keep the user defined password set with pwmd_setopt(). The password may
1389 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
1391 if (!pwm->passfunc && password && password != pwm->password)
1392 pwmd_free(password);
1394 if (rc == GPG_ERR_INV_PASSPHRASE) {
1395 if (++pwm->pin_try < pwm->pinentry_tries) {
1396 if (!get_custom_passphrase(pwm, NULL))
1397 goto done;
1399 #ifdef WITH_PINENTRY
1400 #ifdef WITH_TCP
1401 if (pwm->tcp_conn && !local_pinentry)
1402 return rc;
1403 else if (local_pinentry)
1404 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1405 else
1406 #else
1407 if (local_pinentry)
1408 rc = _getpin(pwm, &password, PWMD_PINENTRY_OPEN_FAILED);
1409 else
1410 #endif
1411 #else
1412 #ifdef WITH_TCP
1413 if (pwm->tcp_conn)
1414 return rc;
1415 else
1416 #endif
1417 #endif
1418 rc = set_pinentry_retry(pwm);
1420 if (rc)
1421 return rc;
1423 goto gotpassword;
1425 #ifdef WITH_PINENTRY
1426 else if (local_pinentry)
1427 _pinentry_disconnect(pwm);
1428 #endif
1430 done:
1431 return rc;
1433 #ifdef WITH_PINENTRY
1434 else if (rc && local_pinentry)
1435 _pinentry_disconnect(pwm);
1436 #endif
1438 if (!rc) {
1439 if (pwm->filename)
1440 pwmd_free(pwm->filename);
1442 pwm->filename = pwmd_strdup(filename);
1445 return rc;
1448 gpg_error_t pwmd_open2(pwm_t *pwm, const char *filename)
1450 #ifndef WITH_PINENTRY
1451 return GPG_ERR_NOT_IMPLEMENTED;
1452 #else
1453 return do_pwmd_open(pwm, filename, 0, 1);
1454 #endif
1457 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
1459 return do_pwmd_open(pwm, filename, 0, 0);
1462 gpg_error_t pwmd_open_async2(pwm_t *pwm, const char *filename)
1464 #ifndef WITH_PINENTRY
1465 return GPG_ERR_NOT_IMPLEMENTED;
1466 #else
1467 if (!pwm || !filename)
1468 return GPG_ERR_INV_ARG;
1470 if (!pwm->ctx)
1471 return GPG_ERR_INV_STATE;
1473 if (pwm->cmd != ASYNC_CMD_NONE)
1474 return GPG_ERR_ASS_NESTED_COMMANDS;
1476 /* Initialize a new command since this is not a pinentry retry. */
1477 if (pwm->lastcmd != ASYNC_CMD_OPEN2)
1478 pwm->pin_try = 0;
1480 pwm->cmd = ASYNC_CMD_OPEN2;
1481 pwm->state = ASYNC_PROCESS;
1482 gpg_error_t rc = do_pwmd_open(pwm, filename, 1, 1);
1484 if (rc)
1485 reset_async(pwm, 0);
1487 return rc;
1488 #endif
1491 static gpg_error_t do_pwmd_save(pwm_t *pwm, int nb, int local_pinentry)
1493 char *result = NULL;
1494 char *password = NULL;
1495 gpg_error_t rc;
1497 if (!pwm)
1498 return GPG_ERR_INV_ARG;
1500 if (!pwm->ctx)
1501 return GPG_ERR_INV_STATE;
1503 rc = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1505 if (rc == GPG_ERR_ENOENT)
1506 rc = GPG_ERR_NOT_FOUND;
1508 if (rc && rc != GPG_ERR_NOT_FOUND)
1509 return rc;
1511 if (rc == GPG_ERR_NOT_FOUND) {
1512 rc = get_custom_passphrase(pwm, &password);
1514 if (rc && rc != GPG_ERR_NO_DATA)
1515 return rc;
1516 else if (rc == GPG_ERR_NO_DATA)
1517 rc = GPG_ERR_NOT_FOUND;
1518 else
1519 goto gotpassword;
1522 if (rc == GPG_ERR_NOT_FOUND && local_pinentry) {
1523 #ifdef WITH_PINENTRY
1524 /* Get the password using the LOCAL pinentry. */
1525 if (nb) {
1526 int p[2];
1527 pid_t pid;
1528 pwmd_nb_status_t pw;
1530 if (pipe(p) == -1)
1531 return gpg_error_from_syserror();
1533 #ifdef WITH_LIBPTH
1534 pid = pth_fork();
1535 #else
1536 pid = fork();
1537 #endif
1539 switch (pid) {
1540 case 0:
1541 close(p[0]);
1542 pw.fd = p[0];
1543 password = NULL;
1544 pw.error = _do_save_getpin(pwm, &password);
1546 if (!pw.error) {
1547 snprintf(pw.password, sizeof(pw.password), "%s",
1548 password);
1549 pwmd_free(password);
1551 #ifdef WITH_LIBPTH
1552 pth_write(p[1], &pw, sizeof(pw));
1553 #else
1554 write(p[1], &pw, sizeof(pw));
1555 #endif
1556 memset(&pw, 0, sizeof(pw));
1557 close(p[1]);
1558 _exit(0);
1559 break;
1560 case -1:
1561 rc = gpg_error_from_syserror();
1562 close(p[0]);
1563 close(p[1]);
1564 return rc;
1565 default:
1566 break;
1569 close(p[1]);
1570 pwm->nb_fd = p[0];
1571 pwm->nb_pid = pid;
1572 return 0;
1575 rc = _do_save_getpin(pwm, &password);
1577 if (rc)
1578 return rc;
1579 #endif
1581 else
1582 pwm->state = ASYNC_DONE;
1584 gotpassword:
1585 reset_async(pwm, 0);
1587 #ifdef WITH_TCP
1588 if (!local_pinentry && !pwm->tcp_conn) {
1589 #else
1590 if (!local_pinentry) {
1591 #endif
1592 rc = send_pinentry_options(pwm);
1594 if (rc)
1595 return rc;
1598 rc = pwmd_command(pwm, NULL, "SAVE %s", password ? password : "");
1600 if (!pwm->passfunc && password && password != pwm->password)
1601 pwmd_free(password);
1603 return rc;
1606 gpg_error_t pwmd_save_async2(pwm_t *pwm)
1608 #ifndef WITH_PINENTRY
1609 return GPG_ERR_NOT_IMPLEMENTED;
1610 #else
1611 if (!pwm)
1612 return GPG_ERR_INV_ARG;
1614 if (!pwm->ctx)
1615 return GPG_ERR_INV_STATE;
1617 if (pwm->cmd != ASYNC_CMD_NONE)
1618 return GPG_ERR_ASS_NESTED_COMMANDS;
1620 pwm->cmd = ASYNC_CMD_SAVE2;
1621 pwm->state = ASYNC_PROCESS;
1622 gpg_error_t rc = do_pwmd_save(pwm, 1, 1);
1624 if (rc)
1625 reset_async(pwm, 0);
1627 return rc;
1628 #endif
1631 gpg_error_t pwmd_save2(pwm_t *pwm)
1633 #ifndef WITH_PINENTRY
1634 return GPG_ERR_NOT_IMPLEMENTED;
1635 #else
1636 return do_pwmd_save(pwm, 0, 1);
1637 #endif
1640 gpg_error_t pwmd_save(pwm_t *pwm)
1642 return do_pwmd_save(pwm, 0, 0);
1645 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1647 va_list ap;
1648 int n = va_arg(ap, int);
1649 char *arg1;
1650 gpg_error_t rc = 0;
1652 if (!pwm)
1653 return GPG_ERR_INV_ARG;
1655 va_start(ap, opt);
1657 switch (opt) {
1658 case PWMD_OPTION_STATUS_CB:
1659 pwm->status_func = va_arg(ap, pwmd_status_cb_t);
1660 break;
1661 case PWMD_OPTION_STATUS_DATA:
1662 pwm->status_data = va_arg(ap, void *);
1663 break;
1664 case PWMD_OPTION_PASSPHRASE_CB:
1665 pwm->passfunc = va_arg(ap, pwmd_passphrase_cb_t);
1666 break;
1667 case PWMD_OPTION_PASSPHRASE_DATA:
1668 pwm->passdata = va_arg(ap, void *);
1669 break;
1670 case PWMD_OPTION_PASSPHRASE:
1671 arg1 = va_arg(ap, char *);
1673 if (pwm->password)
1674 pwmd_free(pwm->password);
1676 pwm->password = pwmd_strdup(arg1);
1677 break;
1678 case PWMD_OPTION_PINENTRY_TRIES:
1679 n = va_arg(ap, int);
1681 if (n <= 0) {
1682 va_end(ap);
1683 rc = GPG_ERR_INV_VALUE;
1685 else
1686 pwm->pinentry_tries = n;
1687 break;
1688 case PWMD_OPTION_PINENTRY_TIMEOUT:
1689 n = va_arg(ap, int);
1691 if (n < 0) {
1692 va_end(ap);
1693 rc = GPG_ERR_INV_VALUE;
1695 else
1696 pwm->pinentry_timeout = n;
1697 break;
1698 case PWMD_OPTION_PINENTRY_PATH:
1699 if (pwm->pinentry_path)
1700 pwmd_free(pwm->pinentry_path);
1702 pwm->pinentry_path = _expand_homedir(va_arg(ap, char *), NULL);
1703 break;
1704 case PWMD_OPTION_PINENTRY_TTY:
1705 if (pwm->pinentry_tty)
1706 pwmd_free(pwm->pinentry_tty);
1708 pwm->pinentry_tty = pwmd_strdup(va_arg(ap, char *));
1709 break;
1710 case PWMD_OPTION_PINENTRY_DISPLAY:
1711 if (pwm->pinentry_display)
1712 pwmd_free(pwm->pinentry_display);
1714 pwm->pinentry_display = pwmd_strdup(va_arg(ap, char *));
1715 break;
1716 case PWMD_OPTION_PINENTRY_TERM:
1717 if (pwm->pinentry_term)
1718 pwmd_free(pwm->pinentry_term);
1720 pwm->pinentry_term = pwmd_strdup(va_arg(ap, char *));
1721 break;
1722 case PWMD_OPTION_PINENTRY_TITLE:
1723 if (pwm->title)
1724 pwmd_free(pwm->title);
1726 pwm->title = _percent_escape(va_arg(ap, char *));
1727 break;
1728 case PWMD_OPTION_PINENTRY_PROMPT:
1729 if (pwm->prompt)
1730 pwmd_free(pwm->prompt);
1732 pwm->prompt = _percent_escape(va_arg(ap, char *));
1733 break;
1734 case PWMD_OPTION_PINENTRY_DESC:
1735 if (pwm->desc)
1736 pwmd_free(pwm->desc);
1738 pwm->desc = _percent_escape(va_arg(ap, char *));
1739 break;
1740 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1741 if (pwm->lcctype)
1742 pwmd_free(pwm->lcctype);
1744 pwm->lcctype = pwmd_strdup(va_arg(ap, char *));
1745 break;
1746 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1747 if (pwm->lcmessages)
1748 pwmd_free(pwm->lcmessages);
1750 pwm->lcmessages = pwmd_strdup(va_arg(ap, char *));
1751 break;
1752 case PWMD_OPTION_IP_VERSION:
1753 #ifdef WITH_TCP
1754 n = va_arg(ap, int);
1756 switch (n) {
1757 case PWMD_IP_ANY:
1758 case PWMD_IPV4:
1759 case PWMD_IPV6:
1760 pwm->prot = n;
1761 break;
1762 default:
1763 rc = GPG_ERR_INV_VALUE;
1764 break;
1767 va_end(ap);
1768 #else
1769 rc = GPG_ERR_NOT_IMPLEMENTED;
1770 #endif
1771 break;
1772 default:
1773 rc = GPG_ERR_UNKNOWN_OPTION;
1774 break;
1777 va_end(ap);
1778 return rc;
1781 gpg_error_t pwmd_get_fds(pwm_t *pwm, pwmd_fd_t *fds, int *n_fds)
1783 int in_total;
1784 int fd = 0;
1785 #ifdef WITH_TCP
1786 int afds[ARES_GETSOCK_MAXNUM];
1787 int got_sock = 0;
1788 int n, i;
1789 #endif
1791 if (!pwm || !fds || !n_fds || *n_fds <= 0)
1792 return GPG_ERR_INV_ARG;
1794 in_total = *n_fds;
1795 #ifdef WITH_TCP
1796 memset(afds, 0, sizeof(int)*ARES_GETSOCK_MAXNUM);
1797 #endif
1798 memset(fds, 0, sizeof(pwmd_fd_t)*in_total);
1799 *n_fds = 0;
1801 switch (pwm->cmd) {
1802 default:
1803 case ASYNC_CMD_NONE:
1804 case ASYNC_CMD_OPEN:
1805 case ASYNC_CMD_SAVE:
1806 #ifdef WITH_PINENTRY
1807 async1:
1808 #endif
1809 if (pwm->fd == -1)
1810 return GPG_ERR_INV_STATE;
1812 (*n_fds)++;
1813 fds[fd].fd = pwm->fd;
1814 fds[fd++].flags = PWMD_FD_READABLE;
1815 return 0;
1816 #ifdef WITH_PINENTRY
1817 case ASYNC_CMD_OPEN2:
1818 case ASYNC_CMD_SAVE2:
1819 /* The command has already completed (cached or new). */
1820 if (pwm->state == ASYNC_DONE)
1821 return 0;
1823 if (pwm->nb_fd == -1)
1824 return GPG_ERR_INV_STATE;
1826 (*n_fds)++;
1827 fds[fd].fd = pwm->nb_fd;
1828 fds[fd++].flags = PWMD_FD_READABLE;
1829 goto async1;
1830 #endif
1831 #ifdef WITH_TCP
1832 case ASYNC_CMD_DNS:
1833 if (!pwm->tcp_conn || !pwm->tcp_conn->chan)
1834 return GPG_ERR_INV_STATE;
1836 n = ares_getsock(pwm->tcp_conn->chan, afds, ARES_GETSOCK_MAXNUM);
1838 for (i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
1839 got_sock = 0;
1841 if (fd > in_total) {
1842 *n_fds = fd;
1843 return GPG_ERR_ERANGE;
1846 if (ARES_GETSOCK_READABLE(n, i)) {
1847 got_sock++;
1848 fds[fd].flags |= PWMD_FD_READABLE;
1851 if (ARES_GETSOCK_WRITABLE(n, i)) {
1852 got_sock++;
1853 fds[fd].flags |= PWMD_FD_WRITABLE;
1856 if (got_sock)
1857 fds[fd++].fd = afds[i];
1860 *n_fds = fd;
1861 return 0;
1862 case ASYNC_CMD_CONNECT:
1863 case ASYNC_CMD_HOSTKEY:
1864 if (!pwm->tcp_conn || pwm->tcp_conn->fd == -1)
1865 return GPG_ERR_INV_STATE;
1867 (*n_fds)++;
1868 fds[fd].fd = pwm->tcp_conn->fd;
1869 fds[fd++].flags = PWMD_FD_READABLE;
1870 return 0;
1871 #endif
1874 return GPG_ERR_INV_STATE;
1877 pwm_t *pwmd_new(const char *name)
1879 pwm_t *h = pwmd_calloc(1, sizeof(pwm_t));
1881 if (!h)
1882 return NULL;
1884 if (name) {
1885 h->name = pwmd_strdup(name);
1887 if (!h->name) {
1888 pwmd_free(h);
1889 return NULL;
1893 reset_handle(h);
1894 h->pinentry_timeout = -30;
1895 h->pinentry_tries = 3;
1896 #ifdef WITH_TCP
1897 h->prot = PWMD_IP_ANY;
1898 #endif
1900 if (ttyname(STDOUT_FILENO)) {
1901 char buf[256];
1903 ttyname_r(STDOUT_FILENO, buf, sizeof(buf));
1904 h->pinentry_tty = pwmd_strdup(buf);
1906 if (!h->pinentry_tty)
1907 goto fail;
1910 if (getenv("TERM") && h->pinentry_tty) {
1911 h->pinentry_term = pwmd_strdup(getenv("TERM"));
1913 if (!h->pinentry_term)
1914 goto fail;
1917 if (getenv("DISPLAY")) {
1918 h->pinentry_display = pwmd_strdup(getenv("DISPLAY"));
1920 if (!h->pinentry_display)
1921 goto fail;
1924 return h;
1926 fail:
1927 pwmd_close(h);
1928 return NULL;
1931 void pwmd_free(void *ptr)
1933 _xfree(ptr);
1936 void *pwmd_malloc(size_t size)
1938 return _xmalloc(size);
1941 void *pwmd_calloc(size_t nmemb, size_t size)
1943 return _xcalloc(nmemb, size);
1946 void *pwmd_realloc(void *ptr, size_t size)
1948 return _xrealloc(ptr, size);
1951 char *pwmd_strdup(const char *str)
1953 return _xstrdup(str);
1956 char *pwmd_strdup_printf(const char *fmt, ...)
1958 va_list ap, ap2;
1959 int len;
1960 char *buf;
1962 if (!fmt)
1963 return NULL;
1965 va_start(ap, fmt);
1966 va_copy(ap2, ap);
1967 len = vsnprintf(NULL, 0, fmt, ap);
1968 va_end(ap);
1969 buf = pwmd_malloc(++len);
1971 if (buf)
1972 vsnprintf(buf, len, fmt, ap2);
1974 va_end(ap2);
1975 return buf;
1978 gpg_error_t pwmd_getpin(pwm_t *pwm, const char *filename, char **result,
1979 pwmd_pinentry_t which)
1981 #ifndef WITH_PINENTRY
1982 return GPG_ERR_NOT_IMPLEMENTED;
1983 #else
1984 return _pwmd_getpin(pwm, filename, result, which);
1985 #endif