Fix compile-time warning.
[libpwmd.git] / src / libpwmd.c
blob986fd4fabf3cccf0b94eaa4c123be543ba11c9af
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/types.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <sys/wait.h>
38 #include <fcntl.h>
39 #include <pwd.h>
40 #include <time.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 pwmd_free (tcp);
277 #endif
279 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
280 gpg_error_t
281 tcp_connect_common (pwm_t * pwm)
283 struct addrinfo hints = { 0 };
284 int n;
285 char portstr[6];
286 gpg_error_t rc = 0;
288 switch (pwm->prot)
290 case PWMD_IP_ANY:
291 hints.ai_family = AF_UNSPEC;
292 break;
293 case PWMD_IPV4:
294 hints.ai_family = AF_INET;
295 break;
296 case PWMD_IPV6:
297 hints.ai_family = AF_INET6;
298 break;
301 hints.ai_socktype = SOCK_STREAM;
302 snprintf (portstr, sizeof (portstr), "%i", pwm->tcp->port);
303 n = getaddrinfo (pwm->tcp->host, portstr, &hints, &pwm->tcp->addrs);
304 if (n)
306 fprintf (stderr, "%s\n", gai_strerror (n));
307 return GPG_ERR_UNKNOWN_HOST; //FIXME
310 for (pwm->tcp->addr = pwm->tcp->addrs; pwm->tcp->addr;
311 pwm->tcp->addr = pwm->tcp->addrs->ai_next)
313 pwm->fd = socket (pwm->tcp->addr->ai_family, SOCK_STREAM, 0);
314 if (pwm->fd == -1)
316 rc = gpg_error_from_syserror ();
317 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
318 break;
319 continue;
322 if (pwm->socket_timeout)
323 fcntl (pwm->fd, F_SETFL, O_NONBLOCK);
325 if (connect (pwm->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 int n;
331 struct timeval tv = { pwm->socket_timeout, 0 };
332 fd_set wfds;
334 rc = gpg_error_from_syserror ();
335 if (gpg_err_code (rc) != GPG_ERR_EINPROGRESS)
337 close (pwm->fd);
338 pwm->fd = -1;
339 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next)
340 return rc;
343 FD_ZERO (&wfds);
344 FD_SET (pwm->fd, &wfds);
345 n = select (pwm->fd+1, NULL, &wfds, NULL, &tv);
346 rc = 0;
347 if (!n)
348 rc = gpg_error (GPG_ERR_ETIMEDOUT);
349 else if (n != -1)
351 socklen_t len;
353 getsockopt (pwm->fd, SOL_SOCKET, SO_ERROR, &n, &len);
354 if (n)
355 rc = gpg_error_from_errno (n);
357 else if (n == -1)
358 rc = gpg_error_from_syserror ();
360 if (rc)
362 close (pwm->fd);
363 pwm->fd = -1;
364 if (pwm->tcp->addr == pwm->tcp->addrs->ai_next
365 || gpg_err_code (rc) == GPG_ERR_ETIMEDOUT)
366 return rc;
368 else
369 break;
371 else
372 break;
375 if (!rc && pwm->socket_timeout)
376 fcntl (pwm->fd, F_SETFL, 0);
378 return rc;
380 #endif
382 gpg_error_t
383 pwmd_connect (pwm_t * pwm, const char *url, ...)
385 const char *p = url;
386 gpg_error_t rc;
388 if (!pwm)
389 return FINISH (GPG_ERR_INV_ARG);
390 else if (!pwm->ctx)
392 rc = init_handle (pwm);
393 if (rc)
394 return rc;
397 rc = GPG_ERR_UNSUPPORTED_PROTOCOL;
399 if (p && *p == '/')
400 rc = connect_uds (pwm, p);
401 else if (!p || !strncmp (p, "file://", 7))
403 if (p)
404 p += 7;
405 rc = connect_uds (pwm, p);
407 else if (!strncmp (p, "ssh://", 6) || !strncmp (p, "ssh6://", 7) ||
408 !strncmp (p, "ssh4://", 7))
410 #ifndef WITH_SSH
411 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
412 #else
413 char *host = NULL;
414 int port;
415 char *username = NULL;
417 if (!strncmp (p, "ssh6://", 7))
419 pwm->prot = PWMD_IPV6;
420 p += 7;
422 else if (!strncmp (p, "ssh4://", 7))
424 pwm->prot = PWMD_IPV4;
425 p += 7;
427 else
429 pwm->prot = PWMD_IP_ANY;
430 p += 6;
433 rc = _parse_ssh_url (p, &host, &port, &username);
434 if (!rc)
436 va_list ap;
437 char *identity = NULL;
438 char *knownhosts = NULL;
440 va_start (ap, url);
441 identity = va_arg (ap, char *);
443 if (!identity && !pwm->use_agent)
444 rc = GPG_ERR_INV_ARG;
445 else
446 knownhosts = va_arg (ap, char *);
448 va_end (ap);
450 if (!rc)
451 rc = _do_ssh_connect (pwm, host, port, identity, username,
452 knownhosts);
453 if (!rc)
455 rc = _connect_finalize (pwm);
456 if (rc)
458 free_tcp (pwm->tcp);
459 pwm->tcp = NULL;
464 pwmd_free (host);
465 pwmd_free (username);
466 return FINISH (rc);
467 #endif
469 else if (!strncmp (p, "tls://", 6) || !strncmp (p, "tls6://", 7) ||
470 !strncmp (p, "tls4://", 7))
472 #ifndef WITH_GNUTLS
473 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
474 #else
475 char *host = NULL;
476 int port;
478 if (!strncmp (p, "tls6://", 7))
480 pwm->prot = PWMD_IPV6;
481 p += 7;
483 else if (!strncmp (p, "tls4://", 7))
485 pwm->prot = PWMD_IPV4;
486 p += 7;
488 else
490 pwm->prot = PWMD_IP_ANY;
491 p += 6;
494 rc = _parse_tls_url (p, &host, &port);
495 if (!rc)
497 va_list ap;
498 char *clientcert = NULL;
499 char *clientkey = NULL;
500 char *cacert = NULL;
501 char *prio = NULL;
502 char *server_fp = NULL;
504 va_start (ap, url);
505 clientcert = va_arg (ap, char *);
507 if (!clientcert)
508 rc = GPG_ERR_INV_ARG;
509 else
511 clientkey = va_arg (ap, char *);
512 if (!clientkey)
513 rc = GPG_ERR_INV_ARG;
514 else
516 cacert = va_arg (ap, char *);
517 if (!cacert)
518 rc = GPG_ERR_INV_ARG;
519 else
521 prio = va_arg (ap, char *);
522 server_fp = va_arg (ap, char *);
527 va_end (ap);
529 if (!rc)
530 rc = _do_tls_connect (pwm, host, port, clientcert, clientkey,
531 cacert, prio, server_fp, pwm->tls_verify);
532 if (!rc)
534 rc = _connect_finalize (pwm);
535 if (rc)
537 free_tcp (pwm->tcp);
538 pwm->tcp = NULL;
543 pwmd_free (host);
544 return FINISH (rc);
545 #endif
548 return FINISH (rc);
551 static void
552 disconnect (pwm_t * pwm)
554 if (!pwm)
555 return;
557 if (pwm->ctx)
558 assuan_release (pwm->ctx);
560 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
561 free_tcp (pwm->tcp);
562 pwm->tcp = NULL;
563 #endif
564 pwm->ctx = NULL;
565 pwm->fd = -1;
568 void
569 pwmd_close (pwm_t * pwm)
571 if (!pwm)
572 return;
574 disconnect (pwm);
575 pwmd_free (pwm->pinentry_error);
576 pwmd_free (pwm->pinentry_desc);
577 pwmd_free (pwm->pinentry_prompt);
578 pwmd_free (pwm->pinentry_tty);
579 pwmd_free (pwm->pinentry_display);
580 pwmd_free (pwm->pinentry_term);
581 pwmd_free (pwm->pinentry_lcctype);
582 pwmd_free (pwm->pinentry_lcmessages);
583 pwmd_free (pwm->filename);
584 pwmd_free (pwm->name);
586 #ifdef WITH_PINENTRY
587 if (pwm->pctx)
588 _pinentry_disconnect (pwm);
589 #endif
591 pwmd_free (pwm);
594 static gpg_error_t
595 inquire_realloc_cb (void *data, const void *buffer, size_t len)
597 membuf_t *mem = (membuf_t *) data;
598 void *p;
600 if (!buffer)
601 return 0;
603 if ((p = pwmd_realloc (mem->buf, mem->len + len)) == NULL)
604 return gpg_error (GPG_ERR_ENOMEM);
606 mem->buf = p;
607 memcpy ((char *) mem->buf + mem->len, buffer, len);
608 mem->len += len;
609 return 0;
612 static gpg_error_t
613 get_password (pwm_t * pwm, char **result, size_t * len,
614 pwmd_pinentry_t w, int echo)
616 char buf[LINE_MAX] = { 0 }, *p;
617 struct termios told, tnew;
618 char *key = NULL;
620 if (result)
621 *result = NULL;
623 if (len)
624 *len = 0;
626 if (!isatty (STDIN_FILENO))
628 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
629 return GPG_ERR_ENOTTY;
632 if (!echo)
634 if (tcgetattr (STDIN_FILENO, &told) == -1)
635 return gpg_error_from_syserror ();
637 memcpy (&tnew, &told, sizeof (struct termios));
638 tnew.c_lflag &= ~(ECHO);
639 tnew.c_lflag |= ICANON | ECHONL;
641 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
643 int n = errno;
645 tcsetattr (STDIN_FILENO, TCSANOW, &told);
646 return gpg_error_from_errno (n);
650 switch (w)
652 case PWMD_PINENTRY_OPEN:
653 fprintf (stderr, N_("Password for %s: "), pwm->filename);
654 break;
655 case PWMD_PINENTRY_OPEN_FAILED:
656 fprintf (stderr, N_("Invalid password. Password for %s: "),
657 pwm->filename);
658 break;
659 case PWMD_PINENTRY_SAVE:
660 fprintf (stderr, N_("New password for %s: "), pwm->filename);
661 break;
662 case PWMD_PINENTRY_SAVE_CONFIRM:
663 fprintf (stderr, N_("Confirm password: "));
664 break;
665 default:
666 break;
669 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
671 tcsetattr (STDIN_FILENO, TCSANOW, &told);
672 return 0;
675 if (!echo)
676 tcsetattr (STDIN_FILENO, TCSANOW, &told);
678 if (feof (stdin))
680 clearerr (stdin);
681 return GPG_ERR_CANCELED;
684 /* Strip the newline character. */
685 p[strlen (p) - 1] = 0;
687 if (buf[0])
689 key = pwmd_strdup_printf ("%s", p);
690 memset (buf, 0, sizeof (buf));
691 if (!key)
692 return GPG_ERR_ENOMEM;
694 if (result)
695 *result = key;
697 if (len)
698 *len = strlen (key);
700 else
702 if (result)
703 *result = pwmd_strdup ("");
705 if (len)
706 *len = 1;
709 return 0;
712 gpg_error_t
713 pwmd_password (pwm_t * pwm, const char *keyword, char **data, size_t * size)
715 gpg_error_t rc;
716 int new_password = 0;
717 char *password = NULL, *newpass = NULL;
718 int error = 0;
720 if (data)
721 *data = NULL;
723 if (size)
724 *size = 0;
726 if (!strcmp (keyword, "NEW_PASSPHRASE"))
727 new_password = 1;
729 if (!new_password && pwm->pinentry_try)
730 error = 1;
732 again:
733 if (pwm->disable_pinentry)
735 rc = get_password (pwm, &password, size,
736 new_password ? PWMD_PINENTRY_SAVE :
737 error ? PWMD_PINENTRY_OPEN_FAILED :
738 PWMD_PINENTRY_OPEN, 0);
739 if (!rc && new_password)
740 rc = get_password (pwm, &newpass, size, PWMD_PINENTRY_SAVE_CONFIRM,
743 else
745 pwmd_pinentry_t which;
747 if (error)
748 which = new_password
749 ? PWMD_PINENTRY_SAVE_FAILED : PWMD_PINENTRY_OPEN_FAILED;
750 else
751 which = new_password ? PWMD_PINENTRY_SAVE : PWMD_PINENTRY_OPEN;
753 rc = pwmd_getpin (pwm, pwm->filename, &password, size, which);
754 if (!rc && new_password)
755 rc = pwmd_getpin (pwm, pwm->filename, &newpass, size,
756 PWMD_PINENTRY_SAVE_CONFIRM);
759 if (!rc && new_password)
761 if ((!password && newpass) || (!newpass && password)
762 || strcmp (newpass, password))
764 if (pwm->disable_pinentry)
765 fprintf (stderr, N_("Passphrases do not match.\n"));
767 pwmd_free (password);
768 pwmd_free (newpass);
769 password = newpass = NULL;
770 error = 1;
771 goto again;
775 (void) pwmd_getpin (pwm, pwm->filename, NULL, NULL, PWMD_PINENTRY_CLOSE);
776 pwmd_free (newpass);
777 if (!rc && data)
778 *data = password;
780 return rc;
783 static gpg_error_t
784 inquire_cb (void *data, const char *keyword)
786 pwm_t *pwm = (pwm_t *) data;
787 gpg_error_t rc = 0;
788 int free_result = 0;
789 char *result = NULL;
790 int is_password = 0;
791 int new_password = 0;
793 if (!strcmp (keyword, "PASSPHRASE"))
794 is_password = 1;
795 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
796 new_password = 1;
798 /* Shouldn't get this far without a callback. */
799 if (!pwm->override_inquire && !pwm->inquire_func
800 && !is_password && !new_password)
801 return gpg_error (GPG_ERR_ASS_NO_INQUIRE_CB);
803 for (;;)
805 size_t len = 0;
806 gpg_error_t arc;
808 result = NULL;
810 if (!pwm->override_inquire && (is_password || new_password))
812 free_result = 1;
813 rc = pwmd_password (data, keyword, &result, &len);
814 if (!rc)
815 rc = GPG_ERR_EOF;
817 else
818 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc, &result,
819 &len);
821 cancel:
822 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
824 gpg_error_t trc = rc;
826 /* Cancel this inquire. */
827 rc = assuan_send_data (pwm->ctx, NULL, 1);
828 if (!rc)
830 char *line;
831 size_t len;
833 /* There is a bug (or feature?) in assuan_send_data() that
834 * when cancelling an inquire the next read from the server is
835 * not done until the next command making the next command
836 * fail with GPG_ERR_ASS_UNEXPECTED_CMD.
838 rc = assuan_read_line (pwm->ctx, &line, &len);
840 /* Restore the original error. This differs from the error
841 * returned from the pwmd command (GPG_ERR_CANCELED). This
842 * error is returned to the calling function.
844 if (!rc)
845 rc = trc;
848 break;
851 if (gpg_err_code (rc) == GPG_ERR_EOF || !rc)
853 if (len <= 0 && !result)
855 rc = 0;
856 break;
858 else if ((len <= 0 && result) || (len && !result))
860 rc = gpg_error (GPG_ERR_INV_ARG);
861 break;
864 if (pwm->inquire_maxlen
865 && pwm->inquire_sent + len > pwm->inquire_maxlen)
867 rc = gpg_error (GPG_ERR_TOO_LARGE);
868 if (!free_result)
869 rc = pwm->inquire_func (pwm->inquire_data, keyword, rc,
870 &result, &len);
871 goto cancel;
874 arc = assuan_send_data (pwm->ctx, result, len);
875 if (gpg_err_code (rc) == GPG_ERR_EOF)
877 rc = arc;
878 break;
881 rc = arc;
883 else if (rc)
884 break;
886 if (!rc)
888 pwm->inquire_sent += len;
890 if (pwm->status_func)
892 char buf[ASSUAN_LINELENGTH];
894 snprintf (buf, sizeof (buf), "XFER %lu %lu", pwm->inquire_sent,
895 pwm->inquire_total);
896 rc = pwm->status_func (pwm->status_data, buf);
897 if (rc)
898 continue;
903 if (free_result)
904 pwmd_free (result);
906 return rc;
909 static gpg_error_t
910 parse_assuan_line (pwm_t * pwm)
912 gpg_error_t rc;
913 char *line;
914 size_t len;
916 rc = assuan_read_line (pwm->ctx, &line, &len);
917 if (!rc)
919 if (line[0] == 'O' && line[1] == 'K' &&
920 (line[2] == 0 || line[2] == ' '))
923 else if (line[0] == '#')
926 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' '))
928 if (pwm->status_func)
930 rc = pwm->status_func (pwm->status_data,
931 line[1] == 0 ? line + 1 : line + 2);
934 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
935 (line[3] == 0 || line[3] == ' '))
937 line += 4;
938 rc = strtol (line, NULL, 10);
942 return rc;
945 static void
946 reset_handle_state (pwm_t * pwm, int done)
948 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
949 if (pwm->tcp)
950 pwm->tcp->rc = 0;
952 if (done)
954 free_tcp (pwm->tcp);
955 pwm->tcp = NULL;
957 #endif
960 static void
961 reset_handle (pwm_t * h)
963 h->fd = -1;
964 #ifdef WITH_PINENTRY
965 if (h->pctx)
966 _pinentry_disconnect (h);
967 #endif
968 reset_handle_state (h, 0);
971 gpg_error_t
972 pwmd_disconnect (pwm_t * pwm)
974 if (!pwm)
975 return FINISH (GPG_ERR_INV_ARG);
977 if (pwm->fd == -1)
978 return FINISH (GPG_ERR_INV_STATE);
980 disconnect (pwm);
981 reset_handle (pwm);
982 return 0;
985 /* Note that this should only be called when not in a command. */
986 gpg_error_t
987 pwmd_process (pwm_t * pwm)
989 gpg_error_t rc = 0;
990 fd_set fds;
991 struct timeval tv = { 0, 0 };
992 int n;
994 if (!pwm)
995 return FINISH (GPG_ERR_INV_ARG);
996 else if (!pwm->ctx)
997 return FINISH (GPG_ERR_INV_STATE);
999 FD_ZERO (&fds);
1000 FD_SET (pwm->fd, &fds);
1001 n = select (pwm->fd + 1, &fds, NULL, NULL, &tv);
1003 if (n == -1)
1004 return FINISH (gpg_error_from_syserror ());
1006 if (n > 0)
1008 if (FD_ISSET (pwm->fd, &fds))
1009 rc = parse_assuan_line (pwm);
1012 while (!rc && assuan_pending_line (pwm->ctx))
1013 rc = parse_assuan_line (pwm);
1015 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1016 if (gpg_err_code (rc) == GPG_ERR_EOF && pwm->tcp)
1018 close (pwm->fd);
1019 pwm->fd = -1;
1021 #endif
1023 return FINISH (rc);
1026 static gpg_error_t
1027 status_cb (void *data, const char *line)
1029 pwm_t *pwm = data;
1031 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
1032 pwm->inquire_maxlen = strtol (line + 15, NULL, 10);
1034 if (pwm->status_func)
1035 return pwm->status_func (pwm->status_data, line);
1037 return 0;
1040 gpg_error_t
1041 _assuan_command (pwm_t * pwm, assuan_context_t ctx,
1042 char **result, size_t * len, const char *cmd)
1044 membuf_t data;
1045 gpg_error_t rc;
1047 if (!cmd || !*cmd)
1048 return FINISH (GPG_ERR_INV_ARG);
1050 if (strlen (cmd) >= ASSUAN_LINELENGTH + 1)
1051 return FINISH (GPG_ERR_LINE_TOO_LONG);
1053 data.len = 0;
1054 data.buf = NULL;
1055 rc = assuan_transact (ctx, cmd, inquire_realloc_cb, &data,
1056 #ifdef WITH_QUALITY
1057 pwm->pctx == ctx ? pwm->_inquire_func : inquire_cb,
1058 pwm->pctx == ctx ? pwm->_inquire_data : pwm,
1059 #else
1060 inquire_cb, pwm,
1061 #endif
1062 status_cb, pwm);
1064 if (rc)
1066 if (data.buf)
1068 pwmd_free (data.buf);
1069 data.buf = NULL;
1072 else
1074 if (data.buf)
1076 inquire_realloc_cb (&data, "", 1);
1078 if (result)
1079 *result = (char *) data.buf;
1080 else
1081 pwmd_free (data.buf);
1083 if (len)
1084 *len = data.len;
1088 pwm->inquire_maxlen = 0;
1089 return rc;
1092 gpg_error_t
1093 pwmd_command_ap (pwm_t * pwm, char **result, size_t * rlen,
1094 pwmd_inquire_cb_t func, void *user, const char *cmd,
1095 va_list ap)
1097 char *buf;
1098 size_t len;
1099 va_list ap2;
1101 if (!pwm || !cmd)
1102 return FINISH (GPG_ERR_INV_ARG);
1103 if (!pwm->ctx)
1104 return FINISH (GPG_ERR_INV_STATE);
1107 * C99 allows the dst pointer to be null which will calculate the length
1108 * of the would-be result and return it.
1110 va_copy (ap2, ap);
1111 len = vsnprintf (NULL, 0, cmd, ap) + 1;
1112 buf = (char *) pwmd_malloc (len);
1113 if (!buf)
1115 va_end (ap2);
1116 return FINISH (GPG_ERR_ENOMEM);
1119 len = vsnprintf (buf, len, cmd, ap2);
1120 va_end (ap2);
1122 if (buf[strlen (buf) - 1] == '\n')
1123 buf[strlen (buf) - 1] = 0;
1124 if (buf[strlen (buf) - 1] == '\r')
1125 buf[strlen (buf) - 1] = 0;
1127 pwm->inquire_func = func;
1128 pwm->inquire_data = user;
1129 pwm->inquire_sent = 0;
1130 gpg_error_t rc = _assuan_command (pwm, pwm->ctx, result, rlen, buf);
1131 pwmd_free (buf);
1132 return rc;
1135 gpg_error_t
1136 pwmd_command (pwm_t * pwm, char **result, size_t * len,
1137 pwmd_inquire_cb_t func, void *user, const char *cmd, ...)
1139 va_list ap;
1141 if (!pwm || !cmd)
1142 return FINISH (GPG_ERR_INV_ARG);
1143 if (!pwm->ctx)
1144 return FINISH (GPG_ERR_INV_STATE);
1146 if (result)
1147 *result = NULL;
1149 va_start (ap, cmd);
1150 gpg_error_t rc = pwmd_command_ap (pwm, result, len, func, user, cmd, ap);
1151 va_end (ap);
1152 return rc;
1155 static gpg_error_t
1156 send_pinentry_options (pwm_t * pwm)
1158 gpg_error_t rc;
1160 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1161 "OPTION disable-pinentry=0");
1162 if (rc)
1163 return rc;
1165 if (pwm->pinentry_tty)
1167 rc =
1168 pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYNAME=%s",
1169 pwm->pinentry_tty);
1170 if (rc)
1171 return rc;
1174 if (pwm->pinentry_term)
1176 rc =
1177 pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION TTYTYPE=%s",
1178 pwm->pinentry_term);
1179 if (rc)
1180 return rc;
1183 if (pwm->pinentry_display)
1185 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DISPLAY=%s",
1186 pwm->pinentry_display);
1187 if (rc)
1188 return rc;
1191 if (pwm->pinentry_desc)
1193 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION DESC=%s",
1194 pwm->pinentry_desc);
1195 if (rc)
1196 return rc;
1199 if (pwm->pinentry_lcctype)
1201 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_CTYPE=%s",
1202 pwm->pinentry_lcctype);
1203 if (rc)
1204 return rc;
1207 if (pwm->pinentry_lcmessages)
1209 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION LC_MESSAGES=%s",
1210 pwm->pinentry_lcmessages);
1211 if (rc)
1212 return rc;
1215 return 0;
1218 gpg_error_t
1219 pwmd_socket_type (pwm_t * pwm, pwmd_socket_t * result)
1221 if (!pwm || !result)
1222 return FINISH (GPG_ERR_INV_ARG);
1224 *result = PWMD_SOCKET_LOCAL;
1226 if (pwm->fd == -1)
1227 return FINISH (GPG_ERR_INV_STATE);
1229 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1230 #ifdef WITH_SSH
1231 if (pwm->tcp && pwm->tcp->ssh)
1232 *result = PWMD_SOCKET_SSH;
1233 #endif
1234 #ifdef WITH_GNUTLS
1235 if (pwm->tcp && pwm->tcp->tls)
1236 *result = PWMD_SOCKET_TLS;
1237 #endif
1238 #endif
1239 return 0;
1242 gpg_error_t
1243 pwmd_open (pwm_t * pwm, const char *filename, pwmd_inquire_cb_t cb,
1244 void *data)
1246 gpg_error_t rc = 0;
1247 int no_pinentry;
1249 if (!pwm || !filename || !*filename)
1250 return FINISH (GPG_ERR_INV_ARG);
1252 if (!pwm->ctx)
1253 return FINISH (GPG_ERR_INV_STATE);
1255 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1256 no_pinentry = pwm->disable_pinentry || pwm->tcp || pwm->local_pinentry;
1257 #else
1258 no_pinentry = pwm->disable_pinentry || pwm->local_pinentry;
1259 #endif
1261 if (!no_pinentry)
1262 rc = send_pinentry_options (pwm);
1263 else
1264 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1265 "OPTION disable-pinentry");
1267 if (!rc)
1269 pwm->pinentry_try = 0;
1270 pwmd_free (pwm->filename);
1271 pwm->filename = pwmd_strdup (filename);
1275 rc = pwmd_command (pwm, NULL, NULL, cb, data, "OPEN %s%s",
1276 (pwm->opts & OPT_LOCK_ON_OPEN) ? "--lock " : "",
1277 filename);
1279 while (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1280 && no_pinentry && ++pwm->pinentry_try < pwm->pinentry_tries);
1282 pwm->pinentry_try = 0;
1284 if (rc)
1286 pwmd_free (pwm->filename);
1287 pwm->filename = NULL;
1291 return FINISH (rc);
1294 gpg_error_t
1295 pwmd_save (pwm_t * pwm, const char *args, pwmd_inquire_cb_t cb, void *data)
1297 gpg_error_t rc;
1299 if (!pwm)
1300 return FINISH (GPG_ERR_INV_ARG);
1301 if (!pwm->ctx)
1302 return FINISH (GPG_ERR_INV_STATE);
1304 rc = pwmd_command (pwm, NULL, NULL, cb, data, "SAVE %s", args ? args : "");
1305 return FINISH (rc);
1308 gpg_error_t
1309 pwmd_setopt (pwm_t * pwm, pwmd_option_t opt, ...)
1311 va_list ap;
1312 int n;
1313 char *arg1;
1314 gpg_error_t rc = 0;
1316 if (!pwm)
1317 return FINISH (GPG_ERR_INV_ARG);
1319 va_start (ap, opt);
1321 switch (opt)
1323 case PWMD_OPTION_LOCK_ON_OPEN:
1324 n = va_arg (ap, int);
1326 if (n < 0 || n > 1)
1327 rc = GPG_ERR_INV_VALUE;
1329 if (n)
1330 pwm->opts |= OPT_LOCK_ON_OPEN;
1331 else
1332 pwm->opts &= ~OPT_LOCK_ON_OPEN;
1334 break;
1335 case PWMD_OPTION_INQUIRE_TOTAL:
1336 pwm->inquire_total = va_arg (ap, size_t);
1337 break;
1338 case PWMD_OPTION_STATUS_CB:
1339 pwm->status_func = va_arg (ap, pwmd_status_cb_t);
1340 break;
1341 case PWMD_OPTION_STATUS_DATA:
1342 pwm->status_data = va_arg (ap, void *);
1343 break;
1344 case PWMD_OPTION_NO_PINENTRY:
1345 n = va_arg (ap, int);
1347 if (n < 0 || n > 1)
1348 rc = GPG_ERR_INV_VALUE;
1349 else
1350 pwm->disable_pinentry = n;
1352 break;
1353 case PWMD_OPTION_LOCAL_PINENTRY:
1354 n = va_arg (ap, int);
1356 if (n < 0 || n > 1)
1357 rc = GPG_ERR_INV_VALUE;
1358 else
1359 pwm->local_pinentry = n;
1361 break;
1362 case PWMD_OPTION_PINENTRY_TIMEOUT:
1363 n = va_arg (ap, int);
1365 if (n < 0)
1366 rc = GPG_ERR_INV_VALUE;
1367 else
1368 pwm->pinentry_timeout = n;
1370 break;
1371 case PWMD_OPTION_PINENTRY_TRIES:
1372 n = va_arg (ap, int);
1373 pwm->pinentry_tries = n;
1374 break;
1375 case PWMD_OPTION_PINENTRY_PATH:
1376 arg1 = va_arg (ap, char *);
1377 pwmd_free (pwm->pinentry_path);
1378 pwm->pinentry_path = arg1 ? _expand_homedir (arg1, NULL) : NULL;
1379 break;
1380 case PWMD_OPTION_PINENTRY_TTY:
1381 arg1 = va_arg (ap, char *);
1382 pwmd_free (pwm->pinentry_tty);
1383 pwm->pinentry_tty = arg1 ? pwmd_strdup (arg1) : NULL;
1384 break;
1385 case PWMD_OPTION_PINENTRY_DISPLAY:
1386 arg1 = va_arg (ap, char *);
1387 pwmd_free (pwm->pinentry_display);
1388 pwm->pinentry_display = arg1 ? pwmd_strdup (arg1) : NULL;
1389 break;
1390 case PWMD_OPTION_PINENTRY_TERM:
1391 arg1 = va_arg (ap, char *);
1392 pwmd_free (pwm->pinentry_term);
1393 pwm->pinentry_term = arg1 ? pwmd_strdup (arg1) : NULL;
1394 break;
1395 case PWMD_OPTION_PINENTRY_ERROR:
1396 arg1 = va_arg (ap, char *);
1397 pwmd_free (pwm->pinentry_error);
1398 pwm->pinentry_error = arg1 ? _percent_escape (arg1) : NULL;
1399 break;
1400 case PWMD_OPTION_PINENTRY_PROMPT:
1401 arg1 = va_arg (ap, char *);
1402 pwmd_free (pwm->pinentry_prompt);
1403 pwm->pinentry_prompt = arg1 ? _percent_escape (arg1) : NULL;
1404 break;
1405 case PWMD_OPTION_PINENTRY_DESC:
1406 arg1 = va_arg (ap, char *);
1407 pwmd_free (pwm->pinentry_desc);
1408 pwm->pinentry_desc = arg1 ? _percent_escape (arg1) : NULL;
1409 break;
1410 case PWMD_OPTION_PINENTRY_LC_CTYPE:
1411 arg1 = va_arg (ap, char *);
1412 pwmd_free (pwm->pinentry_lcctype);
1413 pwm->pinentry_lcctype = arg1 ? pwmd_strdup (arg1) : NULL;
1414 break;
1415 case PWMD_OPTION_PINENTRY_LC_MESSAGES:
1416 arg1 = va_arg (ap, char *);
1417 pwmd_free (pwm->pinentry_lcmessages);
1418 pwm->pinentry_lcmessages = arg1 ? pwmd_strdup (arg1) : NULL;
1419 break;
1420 case PWMD_OPTION_KNOWNHOST_CB:
1421 pwm->kh_cb = va_arg (ap, pwmd_knownhost_cb_t);
1422 break;
1423 case PWMD_OPTION_KNOWNHOST_DATA:
1424 pwm->kh_data = va_arg (ap, void *);
1425 break;
1426 case PWMD_OPTION_SSH_AGENT:
1427 pwm->use_agent = va_arg (ap, int);
1429 if (pwm->use_agent < 0 || pwm->use_agent > 1)
1431 pwm->use_agent = 0;
1432 rc = GPG_ERR_INV_VALUE;
1434 break;
1435 case PWMD_OPTION_TLS_VERIFY:
1436 pwm->tls_verify = va_arg (ap, int);
1438 if (pwm->tls_verify < 0 || pwm->tls_verify > 1)
1440 pwm->tls_verify = 0;
1441 rc = GPG_ERR_INV_VALUE;
1443 break;
1444 case PWMD_OPTION_SOCKET_TIMEOUT:
1445 pwm->socket_timeout = va_arg (ap, int);
1446 if (pwm->socket_timeout < 0)
1448 pwm->socket_timeout = 0;
1449 rc = GPG_ERR_INV_VALUE;
1452 #ifdef WITH_SSH
1453 if (pwm->tcp && pwm->tcp->ssh && pwm->tcp->ssh->session)
1455 pwm->tcp->ssh->timeout = pwm->socket_timeout;
1456 libssh2_session_set_timeout (pwm->tcp->ssh->session,
1457 pwm->socket_timeout * 1000);
1459 #endif
1460 #ifdef WITH_GNUTLS
1461 if (pwm->tcp && pwm->tcp->tls && pwm->tcp->tls->session)
1462 pwm->tcp->tls->timeout = pwm->socket_timeout;
1463 #endif
1464 break;
1465 case PWMD_OPTION_OVERRIDE_INQUIRE:
1466 pwm->override_inquire = va_arg (ap, int);
1468 if (pwm->override_inquire < 0 || pwm->override_inquire > 1)
1470 pwm->override_inquire = 0;
1471 rc = GPG_ERR_INV_VALUE;
1473 break;
1474 default:
1475 rc = GPG_ERR_UNKNOWN_OPTION;
1476 break;
1479 va_end (ap);
1480 return FINISH (rc);
1483 gpg_error_t
1484 pwmd_new (const char *name, pwm_t ** pwm)
1486 pwm_t *h = pwmd_calloc (1, sizeof (pwm_t));
1487 gpg_error_t rc;
1489 if (!h)
1490 return FINISH (GPG_ERR_ENOMEM);
1492 if (name)
1494 h->name = pwmd_strdup (name);
1495 if (!h->name)
1497 pwmd_free (h);
1498 return FINISH (GPG_ERR_ENOMEM);
1502 reset_handle (h);
1503 h->pinentry_timeout = -30;
1504 h->pinentry_tries = 3;
1505 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1506 h->prot = PWMD_IP_ANY;
1507 #endif
1509 if (ttyname (STDOUT_FILENO))
1511 char buf[256];
1513 ttyname_r (STDOUT_FILENO, buf, sizeof (buf));
1514 h->pinentry_tty = pwmd_strdup (buf);
1515 if (!h->pinentry_tty)
1517 rc = GPG_ERR_ENOMEM;
1518 goto fail;
1522 if (getenv ("TERM") && h->pinentry_tty)
1524 h->pinentry_term = pwmd_strdup (getenv ("TERM"));
1525 if (!h->pinentry_term)
1527 rc = GPG_ERR_ENOMEM;
1528 goto fail;
1532 if (getenv ("DISPLAY"))
1534 h->pinentry_display = pwmd_strdup (getenv ("DISPLAY"));
1535 if (!h->pinentry_display)
1537 rc = GPG_ERR_ENOMEM;
1538 goto fail;
1542 update_pinentry_settings (h);
1543 *pwm = h;
1544 return 0;
1546 fail:
1547 pwmd_close (h);
1548 return FINISH (rc);
1551 void
1552 pwmd_free (void *ptr)
1554 _xfree (ptr);
1557 void *
1558 pwmd_malloc (size_t size)
1560 return _xmalloc (size);
1563 void *
1564 pwmd_calloc (size_t nmemb, size_t size)
1566 return _xcalloc (nmemb, size);
1569 void *
1570 pwmd_realloc (void *ptr, size_t size)
1572 return _xrealloc (ptr, size);
1575 char *
1576 pwmd_strdup (const char *str)
1578 char *t;
1579 size_t len;
1580 register size_t c;
1582 len = strlen (str);
1583 t = _xmalloc ((len + 1) * sizeof (char));
1584 if (!t)
1585 return NULL;
1587 for (c = 0; c < len; c++)
1588 t[c] = str[c];
1590 t[c] = 0;
1591 return t;
1594 char *
1595 pwmd_strdup_printf (const char *fmt, ...)
1597 va_list ap, ap2;
1598 int len;
1599 char *buf;
1601 if (!fmt)
1602 return NULL;
1604 va_start (ap, fmt);
1605 va_copy (ap2, ap);
1606 len = vsnprintf (NULL, 0, fmt, ap);
1607 va_end (ap);
1608 buf = pwmd_malloc (++len);
1609 if (buf)
1610 vsnprintf (buf, len, fmt, ap2);
1612 va_end (ap2);
1613 return buf;
1616 gpg_error_t
1617 pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
1618 size_t * len, pwmd_pinentry_t which)
1620 #ifndef WITH_PINENTRY
1621 return FINISH (GPG_ERR_NOT_IMPLEMENTED);
1622 #else
1623 gpg_error_t rc = _pwmd_getpin (pwm, filename, result, len, which);
1625 return FINISH (rc);
1626 #endif
1629 const char *
1630 pwmd_version ()
1632 return LIBPWMD_VERSION_STR;
1635 unsigned int
1636 pwmd_features ()
1638 unsigned int n = 0;
1640 #ifdef WITH_PINENTRY
1641 n |= PWMD_FEATURE_PINENTRY;
1642 #endif
1643 #ifdef WITH_SSH
1644 n |= PWMD_FEATURE_SSH;
1645 #endif
1646 #ifdef WITH_QUALITY
1647 n |= PWMD_FEATURE_CRACK;
1648 #endif
1649 #ifdef WITH_GNUTLS
1650 n |= PWMD_FEATURE_GNUTLS;
1651 #endif
1652 return n;
1655 gpg_error_t
1656 pwmd_fd (pwm_t * pwm, int *fd)
1658 if (!pwm || !fd)
1659 return FINISH (GPG_ERR_INV_ARG);
1661 if (pwm->fd == -1)
1662 return FINISH (GPG_ERR_INV_STATE);
1664 *fd = pwm->fd;
1665 return 0;