Use the correct prompt string when not using pinentry program.
[libpwmd.git] / src / libpwmd.c
blob36e64e382de4fdf0cbcfa01f7af5b90355e601e7
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <err.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <signal.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <sys/wait.h>
37 #include <fcntl.h>
38 #include <pwd.h>
39 #include <time.h>
40 #include <sys/types.h>
41 #include <limits.h>
42 #include <sys/select.h>
43 #include <termios.h>
44 #include <libpwmd.h>
46 #ifdef HAVE_STRINGS_H
47 #include <strings.h>
48 #endif
50 #ifndef LINE_MAX
51 #define LINE_MAX 2048
52 #endif
54 #include "mem.h"
55 #include "misc.h"
56 #include "types.h"
58 #ifdef WITH_PINENTRY
59 #include "pinentry.h"
60 #endif
62 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <netdb.h>
66 #include <netinet/in.h>
67 #endif
69 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
70 ? gpg_error(rc) : rc
72 typedef struct
74 size_t len;
75 void *buf;
76 } membuf_t;
78 ssize_t
79 hook_read (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
81 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
82 pwm_t *pwm = assuan_get_pointer (ctx);
84 #ifdef WITH_SSH
85 if (pwm && pwm->tcp && pwm->tcp->ssh)
86 return read_hook_ssh (pwm->tcp->ssh, fd, data, len);
87 #endif
88 #ifdef WITH_GNUTLS
89 if (pwm && pwm->tcp && pwm->tcp->tls)
90 return read_hook_tls (pwm->tcp->tls, fd, data, len);
91 #endif
92 #endif
94 return read ((int) fd, data, len);
97 ssize_t
98 hook_write (assuan_context_t ctx, assuan_fd_t fd, const void *data,
99 size_t len)
101 ssize_t wrote;
102 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
103 pwm_t *pwm = assuan_get_pointer (ctx);
105 #ifdef WITH_SSH
106 if (pwm && pwm->tcp && pwm->tcp->ssh)
107 return write_hook_ssh (pwm->tcp->ssh, fd, data, len);
108 #endif
109 #ifdef WITH_GNUTLS
110 if (pwm && pwm->tcp && pwm->tcp->tls)
111 return write_hook_tls (pwm->tcp->tls, fd, data, len);
112 #endif
113 #endif
115 /* libassuan cannot handle EAGAIN when doing writes. */
118 wrote = write ((int) fd, data, len);
119 if (wrote == -1 && errno == EAGAIN)
120 usleep (50000);
122 while (wrote == -1 && errno == EAGAIN);
124 return wrote;
127 pid_t
128 hook_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status,
129 int options)
131 return waitpid (pid, status, options);
134 gpg_error_t
135 pwmd_init ()
137 static int initialized;
139 #ifdef WITH_GNUTLS
140 // May be called more than once.
141 gnutls_global_init ();
142 #endif
144 if (initialized)
145 return 0;
147 #ifndef MEM_DEBUG
148 _xmem_init ();
149 #endif
150 #ifdef ENABLE_NLS
151 bindtextdomain ("libpwmd", LOCALEDIR);
152 #endif
153 #ifdef WITH_SSH
154 libssh2_init (0);
155 #endif
156 gpg_err_init ();
157 initialized = 1;
158 return 0;
161 void
162 pwmd_deinit ()
164 #ifdef WITH_GNUTLS
165 gnutls_global_deinit ();
166 #endif
169 gpg_error_t
170 _connect_finalize (pwm_t * pwm)
172 gpg_error_t rc = 0;
173 int active[2];
174 int n = assuan_get_active_fds (pwm->ctx, 0, active, N_ARRAY (active));
176 if (n <= 0)
177 return GPG_ERR_EBADFD;
179 pwm->fd = active[0];
180 #ifdef WITH_PINENTRY
181 pwm->pinentry_pid = -1;
182 #endif
184 if (pwm->name)
185 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION NAME=%s",
186 pwm->name);
188 return rc;
191 static gpg_error_t
192 connect_uds (pwm_t * pwm, const char *path)
194 char *socketpath = NULL;
195 struct passwd pw;
196 char *pwbuf;
197 gpg_error_t rc;
199 if (!pwm)
200 return GPG_ERR_INV_ARG;
202 pwbuf = _getpwuid (&pw);
203 if (!pwbuf)
204 return gpg_error_from_syserror ();
206 if (!path || !*path)
207 socketpath = pwmd_strdup_printf ("%s/.pwmd/socket", pw.pw_dir);
208 else
209 socketpath = _expand_homedir ((char *) path, &pw);
211 pwmd_free (pwbuf);
212 if (!socketpath)
213 return GPG_ERR_ENOMEM;
215 rc = assuan_socket_connect (pwm->ctx, socketpath, ASSUAN_INVALID_FD, 0);
216 pwmd_free (socketpath);
217 return rc ? rc : _connect_finalize (pwm);
220 static gpg_error_t
221 init_handle (pwm_t * pwm)
223 gpg_error_t rc;
224 static struct assuan_malloc_hooks mhooks = {
225 pwmd_malloc, pwmd_realloc, pwmd_free
227 static struct assuan_system_hooks shooks = {
228 ASSUAN_SYSTEM_HOOKS_VERSION,
229 __assuan_usleep,
230 __assuan_pipe,
231 __assuan_close,
232 hook_read,
233 hook_write,
234 //FIXME
235 NULL, //recvmsg
236 NULL, //sendmsg both are used for FD passing
237 __assuan_spawn,
238 hook_waitpid,
239 __assuan_socketpair,
240 __assuan_socket,
241 __assuan_connect
244 rc = assuan_new_ext (&pwm->ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL,
245 NULL);
246 if (rc)
247 return rc;
249 assuan_set_pointer (pwm->ctx, pwm);
250 assuan_ctx_set_system_hooks (pwm->ctx, &shooks);
251 return 0;
254 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
255 void
256 free_tcp (struct tcp_s *tcp)
258 if (!tcp)
259 return;
261 #ifdef WITH_SSH
262 _free_ssh_conn (tcp->ssh);
263 #endif
264 #ifdef WITH_GNUTLS
265 tls_free (tcp->tls);
266 #endif
268 pwmd_free (tcp->host);
269 if (tcp->addrs)
271 freeaddrinfo (tcp->addrs);
272 tcp->addrs = NULL;
275 if (tcp->fd != -1)
276 close (tcp->fd);
278 pwmd_free (tcp);
280 #endif
282 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
283 gpg_error_t
284 tcp_connect_common (pwm_t * pwm)
286 struct addrinfo hints = { 0 };
287 int n;
288 char portstr[6];
289 gpg_error_t rc = 0;
291 switch (pwm->prot)
293 case PWMD_IP_ANY:
294 hints.ai_family = AF_UNSPEC;
295 break;
296 case PWMD_IPV4:
297 hints.ai_family = AF_INET;
298 break;
299 case PWMD_IPV6:
300 hints.ai_family = AF_INET6;
301 break;
304 hints.ai_socktype = SOCK_STREAM;
305 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
306 n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
307 if (n)
309 fprintf (stderr, "%s\n", gai_strerror (n));
310 return GPG_ERR_UNKNOWN_HOST; //FIXME
313 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
314 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
316 pwm->tcp->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
317 if (pwm->tcp->fd == -1)
319 rc = gpg_error_from_syserror ();
320 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
321 break;
322 continue;
325 if (connect (pwm->tcp->fd, pwm->tcp->addr->ai_addr,
326 pwm->tcp->addr->ai_family == AF_INET6
327 ? sizeof (struct sockaddr_in6)
328 : sizeof (struct sockaddr)) == -1)
330 rc = gpg_error_from_syserror ();
331 close (pwm->tcp->fd);
332 pwm->tcp->fd = -1;
333 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
334 break;
335 continue;
338 rc = 0;
339 break;
342 return rc;
344 #endif
346 gpg_error_t
347 pwmd_connect (pwm_t * pwm, const char *url, ...)
349 const char *p = url;
350 gpg_error_t rc;
352 if (!pwm)
353 return FINISH (GPG_ERR_INV_ARG);
354 else if (!pwm->ctx)
356 rc = init_handle (pwm);
357 if (rc)
358 return rc;
361 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
363 if (p && *p == '/')
364 rc = connect_uds (pwm, p);
365 else if (!p || !strncmp (p, "file://", 7))
367 if (p)
368 p += 7;
369 rc = connect_uds (pwm, p);
371 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
372 !strncmp (p, "ssh4://", 7))
374 #ifndef WITH_SSH
375 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
376 #else
377 char *host = NULL;
378 int port;
379 char *username = NULL;
381 if (!strncmp (p, "ssh6://", 7))
383 pwm->prot = PWMD_IPV6;
384 p += 7;
386 else if (!strncmp (p, "ssh4://", 7))
388 pwm->prot = PWMD_IPV4;
389 p += 7;
391 else
393 pwm->prot = PWMD_IP_ANY;
394 p += 6;
397 rc = _parse_ssh_url (p, &host, &port, &username);
398 if (!rc)
400 va_list ap;
401 char *identity = NULL;
402 char *knownhosts = NULL;
404 va_start (ap, url);
405 identity = va_arg (ap, char *);
407 if (!identity && !pwm->use_agent)
408 rc = GPG_ERR_INV_ARG;
409 else
410 knownhosts = va_arg (ap, char *);
412 va_end (ap);
414 if (!rc)
415 rc = _do_ssh_connect (pwm, host, port, identity, username,
416 knownhosts);
417 if (!rc)
419 rc = _connect_finalize (pwm);
420 if (rc)
422 free_tcp (pwm->tcp);
423 pwm->tcp = NULL;
428 pwmd_free (host);
429 pwmd_free (username);
430 return FINISH (rc);
431 #endif
433 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
434 !strncmp (p, "tls4://", 7))
436 #ifndef WITH_GNUTLS
437 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
438 #else
439 char *host = NULL;
440 int port;
442 if (!strncmp (p, "tls6://", 7))
444 pwm->prot = PWMD_IPV6;
445 p += 7;
447 else if (!strncmp (p, "tls4://", 7))
449 pwm->prot = PWMD_IPV4;
450 p += 7;
452 else
454 pwm->prot = PWMD_IP_ANY;
455 p += 6;
458 rc = _parse_tls_url (p, &host, &port);
459 if (!rc)
461 va_list ap;
462 char *clientcert = NULL;
463 char *clientkey = NULL;
464 char *cacert = NULL;
465 char *prio = NULL;
466 char *server_fp = NULL;
468 va_start (ap, url);
469 clientcert = va_arg (ap, char *);
471 if (!clientcert)
472 rc = GPG_ERR_INV_ARG;
473 else
475 clientkey = va_arg (ap, char *);
476 if (!clientkey)
477 rc = GPG_ERR_INV_ARG;
478 else
480 cacert = va_arg (ap, char *);
481 if (!cacert)
482 rc = GPG_ERR_INV_ARG;
483 else
485 prio = va_arg (ap, char *);
486 server_fp = va_arg (ap, char *);
491 va_end (ap);
493 if (!rc)
494 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
495 cacert, prio, server_fp, pwm->tls_verify);
496 if (!rc)
498 rc = _connect_finalize (pwm);
499 if (rc)
501 free_tcp (pwm->tcp);
502 pwm->tcp = NULL;
507 pwmd_free (host);
508 return FINISH (rc);
509 #endif
512 return FINISH (rc);
515 static void
516 disconnect (pwm_t * pwm)
518 if (!pwm)
519 return;
521 if (pwm->ctx)
522 assuan_release (pwm->ctx);
524 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
525 free_tcp (pwm->tcp);
526 pwm->tcp = NULL;
527 #endif
528 pwm->ctx = NULL;
529 pwm->fd = -1;
532 void
533 pwmd_close (pwm_t * pwm)
535 if (!pwm)
536 return;
538 disconnect (pwm);
539 pwmd_free (pwm->pinentry_error);
540 pwmd_free (pwm->pinentry_desc);
541 pwmd_free (pwm->pinentry_prompt);
542 pwmd_free (pwm->pinentry_tty);
543 pwmd_free (pwm->pinentry_display);
544 pwmd_free (pwm->pinentry_term);
545 pwmd_free (pwm->pinentry_lcctype);
546 pwmd_free (pwm->pinentry_lcmessages);
547 pwmd_free (pwm->filename);
548 pwmd_free (pwm->name);
550 #ifdef WITH_PINENTRY
551 if (pwm->pctx)
552 _pinentry_disconnect (pwm);
553 #endif
555 pwmd_free (pwm);
558 static gpg_error_t
559 inquire_realloc_cb (void *data, const void *buffer, size_t len)
561 membuf_t *mem = (membuf_t *) data;
562 void *p;
564 if (!buffer)
565 return 0;
567 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
568 return gpg_error (GPG_ERR_ENOMEM);
570 mem->buf = p;
571 memcpy ((char *) mem->buf + mem->len, buffer, len);
572 mem->len += len;
573 return 0;
576 static gpg_error_t
577 get_password (pwm_t * pwm, char **result, size_t * len,
578 pwmd_pinentry_t w, int echo)
580 char buf[LINE_MAX] = { 0 }, *p;
581 struct termios told, tnew;
582 char *key = NULL;
584 if (result)
585 *result = NULL;
587 if (len)
588 *len = 0;
590 if (!isatty (STDIN_FILENO))
592 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
593 return GPG_ERR_ENOTTY;
596 if (!echo)
598 if (tcgetattr (STDIN_FILENO, &told) == -1)
599 return gpg_error_from_syserror ();
601 memcpy (&tnew, &told, sizeof (struct termios));
602 tnew.c_lflag &= ~(ECHO);
603 tnew.c_lflag |= ICANON | ECHONL;
605 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
607 int n = errno;
609 tcsetattr (STDIN_FILENO, TCSANOW, &told);
610 return gpg_error_from_errno (n);
614 switch (w)
616 case PWMD_PINENTRY_OPEN:
617 fprintf (stderr, N_("Password for %s: "), pwm->filename);
618 break;
619 case PWMD_PINENTRY_OPEN_FAILED:
620 fprintf (stderr, N_("Invalid password. Password for %s: "),
621 pwm->filename);
622 break;
623 case PWMD_PINENTRY_SAVE:
624 fprintf (stderr, N_("New password for %s: "), pwm->filename);
625 break;
626 case PWMD_PINENTRY_SAVE_CONFIRM:
627 fprintf (stderr, N_("Confirm password: "));
628 break;
629 default:
630 break;
633 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
635 tcsetattr (STDIN_FILENO, TCSANOW, &told);
636 return 0;
639 if (!echo)
640 tcsetattr (STDIN_FILENO, TCSANOW, &told);
642 if (feof (stdin))
644 clearerr (stdin);
645 return GPG_ERR_CANCELED;
648 /* Strip the newline character. */
649 p[strlen (p) - 1] = 0;
651 if (buf[0])
653 key = pwmd_strdup_printf ("%s", p);
654 memset (buf, 0, sizeof (buf));
655 if (!key)
656 return GPG_ERR_ENOMEM;
658 if (result)
659 *result = key;
661 if (len)
662 *len = strlen (key);
664 else
666 if (result)
667 *result = pwmd_strdup ("");
669 if (len)
670 *len = 1;
673 return 0;
676 gpg_error_t
677 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
679 gpg_error_t rc;
680 int new_password = 0;
681 char *password = NULL, *newpass = NULL;
682 int error = 0;
684 if (data)
685 *data = NULL;
687 if (size)
688 *size = 0;
690 if (!strcmp (keyword, "NEW_PASSPHRASE"))
691 new_password = 1;
693 if (!new_password && pwm->pinentry_try)
694 error = 1;
696 again:
697 if (pwm->disable_pinentry)
699 rc = get_password (pwm, &password, size,
700 new_password ? PWMD_PINENTRY_SAVE :
701 error ? PWMD_PINENTRY_OPEN_FAILED :
702 PWMD_PINENTRY_OPEN, 0);
703 if (!rc && new_password)
704 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
707 else
709 pwmd_pinentry_t which;
711 if (error)
712 which = new_password
713 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
714 else
715 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
717 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
718 if (!rc && new_password)
719 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
720 PWMD_PINENTRY_SAVE_CONFIRM);
723 if (!rc && new_password)
725 if ((!password && newpass) || (!newpass && password)
726 || strcmp (newpass, password))
728 if (pwm->disable_pinentry)
729 fprintf (stderr, N_("Passphrases do not match.\n"));
731 pwmd_free (password);
732 pwmd_free (newpass);
733 password = newpass = NULL;
734 error = 1;
735 goto again;
739 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
740 pwmd_free (newpass);
741 if (!rc && data)
742 *data = password;
744 return rc;
747 static gpg_error_t
748 inquire_cb (void *data, const char *keyword)
750 pwm_t *pwm = (pwm_t *) data;
751 gpg_error_t rc = 0;
752 int free_result = 0;
753 char *result = NULL;
755 /* Shouldn't get this far without a callback. */
756 if (!pwm->override_inquire && !pwm->inquire_func)
757 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
759 for (;;)
761 size_t len = 0;
762 gpg_error_t arc;
763 int is_password = 0;
764 int new_password = 0;
766 result = NULL;
768 if (!strcmp (keyword, "PASSPHRASE"))
769 is_password = 1;
770 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
771 new_password = 1;
773 if (!pwm->override_inquire && (is_password || new_password))
775 free_result = 1;
776 rc = pwmd_password (data, keyword, &result, &len);
777 if (!rc)
778 rc = GPG_ERR_EOF;
780 else
781 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
782 &len);
784 cancel:
785 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
787 gpg_error_t trc = rc;
789 /* Cancel this inquire. */
790 rc = assuan_send_data (pwm->ctx, NULL, 1);
791 if (!rc)
793 char *line;
794 size_t len;
796 /* There is a bug (or feature?) in assuan_send_data() that
797 * when cancelling an inquire the next read from the server is
798 * not done until the next command making the next command
799 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
801 rc = assuan_read_line (pwm->ctx, &line, &len);
803 /* Restore the original error. This differs from the error
804 * returned from the pwmd command (GPG_ERR_CANCELED). This
805 * error is returned to the calling function.
807 if (!rc)
808 rc = trc;
811 break;
814 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
816 if (len <= 0 && !result)
818 rc = 0;
819 break;
821 else if ((len <= 0 && result) || (len && !result))
823 rc = gpg_error (GPG_ERR_INV_ARG);
824 break;
827 if (pwm->inquire_maxlen
828 && pwm->inquire_sent + len > pwm->inquire_maxlen)
830 rc = gpg_error (GPG_ERR_TOO_LARGE);
831 if (!free_result)
832 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
833 &result, &len);
834 goto cancel;
837 arc = assuan_send_data (pwm->ctx, result, len);
838 if (gpg_err_code (rc) == GPG_ERR_EOF)
840 rc = arc;
841 break;
844 rc = arc;
846 else if (rc)
847 break;
849 if (!rc)
851 pwm->inquire_sent += len;
853 if (pwm->status_func)
855 char buf[ASSUAN_LINELENGTH];
857 snprintf (buf, sizeof (buf), "XFER %lu %lu", pwm->inquire_sent,
858 pwm->inquire_total);
859 rc = pwm->status_func (pwm->status_data, buf);
860 if (rc)
861 continue;
866 if (free_result)
867 pwmd_free (result);
869 return rc;
872 static gpg_error_t
873 parse_assuan_line (pwm_t * pwm)
875 gpg_error_t rc;
876 char *line;
877 size_t len;
879 rc = assuan_read_line (pwm->ctx, &line, &len);
880 if (!rc)
882 if (line[0] == 'O' && line[1] == 'K' &&
883 (line[2] == 0 || line[2] == ' '))
886 else if (line[0] == '#')
889 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
891 if (pwm->status_func)
893 rc = pwm->status_func (pwm->status_data,
894 line[1] == 0 ? line + 1 : line + 2);
897 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
898 (line[3] == 0 || line[3] == ' '))
900 line += 4;
901 rc = strtol (line, NULL, 10);
905 return rc;
908 static void
909 reset_handle_state (pwm_t * pwm, int done)
911 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
912 if (pwm->tcp)
913 pwm->tcp->rc = 0;
915 if (done)
917 free_tcp (pwm->tcp);
918 pwm->tcp = NULL;
920 #endif
923 static void
924 reset_handle (pwm_t * h)
926 h->fd = -1;
927 #ifdef WITH_PINENTRY
928 if (h->pctx)
929 _pinentry_disconnect (h);
930 #endif
931 reset_handle_state (h, 0);
934 gpg_error_t
935 pwmd_disconnect (pwm_t * pwm)
937 if (!pwm)
938 return FINISH (GPG_ERR_INV_ARG);
940 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
941 if (pwm->fd == -1 && pwm->tcp && pwm->tcp->fd == -1)
942 #else
943 if (pwm->fd == -1)
944 #endif
945 return FINISH (GPG_ERR_INV_STATE);
947 if (pwm->fd != 1)
948 disconnect (pwm);
950 reset_handle (pwm);
951 return 0;
954 /* Note that this should only be called when not in a command. */
955 gpg_error_t
956 pwmd_process (pwm_t * pwm)
958 gpg_error_t rc = 0;
959 fd_set fds;
960 struct timeval tv = { 0, 0 };
961 int n;
963 if (!pwm)
964 return FINISH (GPG_ERR_INV_ARG);
965 else if (!pwm->ctx)
966 return FINISH (GPG_ERR_INV_STATE);
968 FD_ZERO (&fds);
969 FD_SET (pwm->fd, &fds);
970 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
972 if (n == -1)
973 return FINISH (gpg_error_from_syserror ());
975 if (n > 0)
977 if (FD_ISSET (pwm->fd, &fds))
978 rc = parse_assuan_line (pwm);
981 while (!rc && assuan_pending_line (pwm->ctx))
982 rc = parse_assuan_line (pwm);
984 return FINISH (rc);
987 static gpg_error_t
988 status_cb (void *data, const char *line)
990 pwm_t *pwm = data;
992 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
993 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
995 if (pwm->status_func)
996 return pwm->status_func (pwm->status_data, line);
998 return 0;
1001 gpg_error_t
1002 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1003 char **result, size_t * len, const char *cmd)
1005 membuf_t data;
1006 gpg_error_t rc;
1008 if (!cmd || !*cmd)
1009 return FINISH (GPG_ERR_INV_ARG);
1011 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1012 return FINISH (GPG_ERR_LINE_TOO_LONG);
1014 data.len = 0;
1015 data.buf = NULL;
1016 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1017 #ifdef WITH_QUALITY
1018 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1019 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1020 #else
1021 inquire_cb, pwm,
1022 #endif
1023 status_cb, pwm);
1025 if (rc)
1027 if (data.buf)
1029 pwmd_free (data.buf);
1030 data.buf = NULL;
1033 else
1035 if (data.buf)
1037 inquire_realloc_cb (&data, "", 1);
1039 if (result)
1040 *result = (char *) data.buf;
1041 else
1042 pwmd_free (data.buf);
1044 if (len)
1045 *len = data.len;
1049 pwm->inquire_maxlen = 0;
1050 return rc;
1053 gpg_error_t
1054 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1055 pwmd_inquire_cb_t func, void *user, const char *cmd,
1056 va_list ap)
1058 char *buf;
1059 size_t len;
1060 va_list ap2;
1062 if (!pwm || !cmd)
1063 return FINISH (GPG_ERR_INV_ARG);
1064 if (!pwm->ctx)
1065 return FINISH (GPG_ERR_INV_STATE);
1068 * C99 allows the dst pointer to be null which will calculate the length
1069 * of the would-be result and return it.
1071 va_copy (ap2, ap);
1072 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1073 buf = (char *) pwmd_malloc (len);
1074 if (!buf)
1076 va_end (ap2);
1077 return FINISH (GPG_ERR_ENOMEM);
1080 len = vsnprintf (buf, len, cmd, ap2);
1081 va_end (ap2);
1083 if (buf[strlen (buf) - 1] == '\n')
1084 buf[strlen (buf) - 1] = 0;
1085 if (buf[strlen (buf) - 1] == '\r')
1086 buf[strlen (buf) - 1] = 0;
1088 pwm->inquire_func = func;
1089 pwm->inquire_data = user;
1090 pwm->inquire_sent = 0;
1091 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1092 pwmd_free (buf);
1093 return rc;
1096 gpg_error_t
1097 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1098 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1100 va_list ap;
1102 if (!pwm || !cmd)
1103 return FINISH (GPG_ERR_INV_ARG);
1104 if (!pwm->ctx)
1105 return FINISH (GPG_ERR_INV_STATE);
1107 if (result)
1108 *result = NULL;
1110 va_start (ap, cmd);
1111 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1112 va_end (ap);
1113 return rc;
1116 static gpg_error_t
1117 send_pinentry_options (pwm_t * pwm)
1119 gpg_error_t rc;
1121 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1122 "OPTION disable-pinentry=0");
1123 if (rc)
1124 return rc;
1126 if (pwm->pinentry_tty)
1128 rc =
1129 pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1130 pwm->pinentry_tty);
1131 if (rc)
1132 return rc;
1135 if (pwm->pinentry_term)
1137 rc =
1138 pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1139 pwm->pinentry_term);
1140 if (rc)
1141 return rc;
1144 if (pwm->pinentry_display)
1146 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1147 pwm->pinentry_display);
1148 if (rc)
1149 return rc;
1152 if (pwm->pinentry_desc)
1154 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1155 pwm->pinentry_desc);
1156 if (rc)
1157 return rc;
1160 if (pwm->pinentry_lcctype)
1162 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1163 pwm->pinentry_lcctype);
1164 if (rc)
1165 return rc;
1168 if (pwm->pinentry_lcmessages)
1170 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1171 pwm->pinentry_lcmessages);
1172 if (rc)
1173 return rc;
1176 return 0;
1179 gpg_error_t
1180 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1182 if (!pwm || !result)
1183 return FINISH (GPG_ERR_INV_ARG);
1185 *result = PWMD_SOCKET_LOCAL;
1187 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1188 if ((pwm->fd == -1 && (!pwm->tcp
1189 #ifdef WITH_SSH
1190 || !pwm->tcp->ssh
1191 #endif
1192 #ifdef WITH_GNUTLS
1193 || !pwm->tcp->tls
1194 #endif
1195 )) || (pwm->fd == -1 && pwm->tcp && pwm->tcp->fd == -1))
1196 return FINISH (GPG_ERR_INV_STATE);
1197 #else
1198 if (pwm->fd == -1)
1199 return FINISH (GPG_ERR_INV_STATE);
1200 #endif
1202 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1203 #ifdef WITH_SSH
1204 if (pwm->tcp && pwm->tcp->ssh)
1205 *result = PWMD_SOCKET_SSH;
1206 #endif
1207 #ifdef WITH_GNUTLS
1208 if (pwm->tcp && pwm->tcp->tls)
1209 *result = PWMD_SOCKET_TLS;
1210 #endif
1211 #endif
1212 return 0;
1215 gpg_error_t
1216 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1217 void *data)
1219 gpg_error_t rc = 0;
1220 int no_pinentry;
1222 if (!pwm || !filename || !*filename)
1223 return FINISH (GPG_ERR_INV_ARG);
1225 if (!pwm->ctx)
1226 return FINISH (GPG_ERR_INV_STATE);
1228 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1229 no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1230 #else
1231 no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1232 #endif
1234 if (!no_pinentry)
1235 rc = send_pinentry_options (pwm);
1236 else
1237 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1238 "OPTION disable-pinentry");
1240 if (!rc)
1242 pwm->pinentry_try = 0;
1243 pwmd_free (pwm->filename);
1244 pwm->filename = pwmd_strdup (filename);
1248 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1249 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1250 filename);
1252 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1253 && no_pinentry && ++pwm->pinentry_try < pwm->pinentry_tries);
1255 pwm->pinentry_try = 0;
1257 if (rc)
1259 pwmd_free (pwm->filename);
1260 pwm->filename = NULL;
1264 return FINISH (rc);
1267 gpg_error_t
1268 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1270 gpg_error_t rc;
1272 if (!pwm)
1273 return FINISH (GPG_ERR_INV_ARG);
1274 if (!pwm->ctx)
1275 return FINISH (GPG_ERR_INV_STATE);
1277 rc = pwmd_command (pwm, NULL, NULL, cb, data, "SAVE %s", args ? args : "");
1278 return FINISH (rc);
1281 gpg_error_t
1282 pwmd_setopt (pwm_t * pwm, pwmd_option_t opt, ...)
1284 va_list ap;
1285 int n;
1286 char *arg1;
1287 gpg_error_t rc = 0;
1289 if (!pwm)
1290 return FINISH (GPG_ERR_INV_ARG);
1292 va_start (ap, opt);
1294 switch (opt)
1296 case PWMD_OPTION_LOCK_ON_OPEN:
1297 n = va_arg (ap, int);
1299 if (n < 0 || n > 1)
1300 rc = GPG_ERR_INV_VALUE;
1302 if (n)
1303 pwm->opts |= OPT_LOCK_ON_OPEN;
1304 else
1305 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1307 break;
1308 case PWMD_OPTION_INQUIRE_TOTAL:
1309 pwm->inquire_total = va_arg (ap, size_t);
1310 break;
1311 case PWMD_OPTION_STATUS_CB:
1312 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1313 break;
1314 case PWMD_OPTION_STATUS_DATA:
1315 pwm->status_data = va_arg (ap, void *);
1316 break;
1317 case PWMD_OPTION_NO_PINENTRY:
1318 n = va_arg (ap, int);
1320 if (n < 0 || n > 1)
1321 rc = GPG_ERR_INV_VALUE;
1322 else
1323 pwm->disable_pinentry = n;
1325 break;
1326 case PWMD_OPTION_LOCAL_PINENTRY:
1327 n = va_arg (ap, int);
1329 if (n < 0 || n > 1)
1330 rc = GPG_ERR_INV_VALUE;
1331 else
1332 pwm->local_pinentry = n;
1334 break;
1335 case PWMD_OPTION_PINENTRY_TIMEOUT:
1336 n = va_arg (ap, int);
1338 if (n < 0)
1339 rc = GPG_ERR_INV_VALUE;
1340 else
1341 pwm->pinentry_timeout = n;
1343 break;
1344 case PWMD_OPTION_PINENTRY_TRIES:
1345 n = va_arg (ap, int);
1346 pwm->pinentry_tries = n;
1347 break;
1348 case PWMD_OPTION_PINENTRY_PATH:
1349 arg1 = va_arg (ap, char *);
1350 pwmd_free (pwm->pinentry_path);
1351 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1352 break;
1353 case PWMD_OPTION_PINENTRY_TTY:
1354 arg1 = va_arg (ap, char *);
1355 pwmd_free (pwm->pinentry_tty);
1356 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1357 break;
1358 case PWMD_OPTION_PINENTRY_DISPLAY:
1359 arg1 = va_arg (ap, char *);
1360 pwmd_free (pwm->pinentry_display);
1361 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1362 break;
1363 case PWMD_OPTION_PINENTRY_TERM:
1364 arg1 = va_arg (ap, char *);
1365 pwmd_free (pwm->pinentry_term);
1366 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1367 break;
1368 case PWMD_OPTION_PINENTRY_ERROR:
1369 arg1 = va_arg (ap, char *);
1370 pwmd_free (pwm->pinentry_error);
1371 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1372 break;
1373 case PWMD_OPTION_PINENTRY_PROMPT:
1374 arg1 = va_arg (ap, char *);
1375 pwmd_free (pwm->pinentry_prompt);
1376 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1377 break;
1378 case PWMD_OPTION_PINENTRY_DESC:
1379 arg1 = va_arg (ap, char *);
1380 pwmd_free (pwm->pinentry_desc);
1381 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1382 break;
1383 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1384 arg1 = va_arg (ap, char *);
1385 pwmd_free (pwm->pinentry_lcctype);
1386 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1387 break;
1388 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1389 arg1 = va_arg (ap, char *);
1390 pwmd_free (pwm->pinentry_lcmessages);
1391 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1392 break;
1393 #ifdef WITH_SSH
1394 case PWMD_OPTION_KNOWNHOST_CB:
1395 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1396 break;
1397 case PWMD_OPTION_KNOWNHOST_DATA:
1398 pwm->kh_data = va_arg (ap, void *);
1399 break;
1400 case PWMD_OPTION_SSH_AGENT:
1401 pwm->use_agent = va_arg (ap, int);
1403 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1405 pwm->use_agent = 0;
1406 rc = GPG_ERR_INV_VALUE;
1409 break;
1410 #else
1411 case PWMD_OPTION_KNOWNHOST_CB:
1412 case PWMD_OPTION_KNOWNHOST_DATA:
1413 case PWMD_OPTION_SSH_AGENT:
1414 rc = GPG_ERR_NOT_IMPLEMENTED;
1415 break;
1416 #endif
1417 #ifdef WITH_GNUTLS
1418 case PWMD_OPTION_TLS_VERIFY:
1419 pwm->tls_verify = va_arg (ap, int);
1421 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1423 pwm->tls_verify = 0;
1424 rc = GPG_ERR_INV_VALUE;
1426 break;
1427 #endif
1428 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1429 case PWMD_OPTION_SOCKET_TIMEOUT:
1430 pwm->socket_timeout = va_arg (ap, int);
1431 if (pwm->socket_timeout < 0)
1433 pwm->socket_timeout = 0;
1434 rc = GPG_ERR_INV_VALUE;
1437 #ifdef WITH_SSH
1438 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1439 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1440 #endif
1441 #ifdef WITH_GNUTLS
1442 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1443 pwm->tcp->tls->timeout = pwm->socket_timeout;
1444 #endif
1445 break;
1446 #else
1447 rc = GPG_ERR_NOT_IMPLEMENTED;
1448 break;
1449 #endif
1450 case PWMD_OPTION_OVERRIDE_INQUIRE:
1451 pwm->override_inquire = va_arg (ap, int);
1453 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1455 pwm->override_inquire = 0;
1456 rc = GPG_ERR_INV_VALUE;
1458 break;
1459 default:
1460 rc = GPG_ERR_UNKNOWN_OPTION;
1461 break;
1464 va_end (ap);
1465 return FINISH (rc);
1468 gpg_error_t
1469 pwmd_new (const char *name, pwm_t ** pwm)
1471 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1472 gpg_error_t rc;
1474 if (!h)
1475 return FINISH (GPG_ERR_ENOMEM);
1477 if (name)
1479 h->name = pwmd_strdup (name);
1480 if (!h->name)
1482 pwmd_free (h);
1483 return FINISH (GPG_ERR_ENOMEM);
1487 reset_handle (h);
1488 h->pinentry_timeout = -30;
1489 h->pinentry_tries = 3;
1490 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1491 h->prot = PWMD_IP_ANY;
1492 #endif
1494 if (ttyname (STDOUT_FILENO))
1496 char buf[256];
1498 ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
1499 h->pinentry_tty = pwmd_strdup (buf);
1500 if (!h->pinentry_tty)
1502 rc = GPG_ERR_ENOMEM;
1503 goto fail;
1507 if (getenv ("TERM") && h->pinentry_tty)
1509 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
1510 if (!h->pinentry_term)
1512 rc = GPG_ERR_ENOMEM;
1513 goto fail;
1517 if (getenv ("DISPLAY"))
1519 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
1520 if (!h->pinentry_display)
1522 rc = GPG_ERR_ENOMEM;
1523 goto fail;
1527 update_pinentry_settings (h);
1528 *pwm = h;
1529 return 0;
1531 fail:
1532 pwmd_close (h);
1533 return FINISH (rc);
1536 void
1537 pwmd_free (void *ptr)
1539 _xfree (ptr);
1542 void *
1543 pwmd_malloc (size_t size)
1545 return _xmalloc (size);
1548 void *
1549 pwmd_calloc (size_t nmemb, size_t size)
1551 return _xcalloc (nmemb, size);
1554 void *
1555 pwmd_realloc (void *ptr, size_t size)
1557 return _xrealloc (ptr, size);
1560 char *
1561 pwmd_strdup (const char *str)
1563 char *t;
1564 size_t len;
1565 register size_t c;
1567 len = strlen (str);
1568 t = _xmalloc ((len + 1) * sizeof (char));
1569 if (!t)
1570 return NULL;
1572 for (c = 0; c < len; c++)
1573 t[c] = str[c];
1575 t[c] = 0;
1576 return t;
1579 char *
1580 pwmd_strdup_printf (const char *fmt, ...)
1582 va_list ap, ap2;
1583 int len;
1584 char *buf;
1586 if (!fmt)
1587 return NULL;
1589 va_start (ap, fmt);
1590 va_copy (ap2, ap);
1591 len = vsnprintf (NULL, 0, fmt, ap);
1592 va_end (ap);
1593 buf = pwmd_malloc (++len);
1594 if (buf)
1595 vsnprintf (buf, len, fmt, ap2);
1597 va_end (ap2);
1598 return buf;
1601 gpg_error_t
1602 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
1603 size_t * len, pwmd_pinentry_t which)
1605 #ifndef WITH_PINENTRY
1606 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
1607 #else
1608 gpg_error_t rc = _pwmd_getpin (pwm, filename, result, len, which);
1610 return FINISH (rc);
1611 #endif
1614 const char *
1615 pwmd_version ()
1617 return LIBPWMD_VERSION_STR;
1620 unsigned int
1621 pwmd_features ()
1623 unsigned int n = 0;
1625 #ifdef WITH_PINENTRY
1626 n |= PWMD_FEATURE_PINENTRY;
1627 #endif
1628 #ifdef WITH_SSH
1629 n |= PWMD_FEATURE_SSH;
1630 #endif
1631 #ifdef WITH_QUALITY
1632 n |= PWMD_FEATURE_CRACK;
1633 #endif
1634 #ifdef WITH_GNUTLS
1635 n |= PWMD_FEATURE_GNUTLS;
1636 #endif
1637 return n;
1640 gpg_error_t
1641 pwmd_fd (pwm_t * pwm, int *fd)
1643 if (!pwm || !fd)
1644 return FINISH (GPG_ERR_INV_ARG);
1646 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1647 if (pwm->tcp && pwm->tcp->fd == -1 && pwm->fd == -1)
1648 return GPG_ERR_INV_STATE;
1650 *fd = pwm->tcp && pwm->tcp->fd != -1 ? pwm->tcp->fd : pwm->fd;
1651 #else
1652 if (pwm->fd == -1)
1653 return FINISH (GPG_ERR_INV_STATE);
1655 *fd = pwm->fd;
1656 #endif
1658 return 0;