When DEBUG is defined, pwmc has a new option -E to specify the
[libpwmd.git] / libpwmd.c
blob3ca5d55923f76e431c467e202f87f274e5636670
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2008 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 02111-1307 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 #ifdef HAVE_SETLOCALE
49 #include <locale.h>
50 #endif
52 #include "gettext.h"
53 #define N_(msgid) dgettext("libpwmd", msgid)
55 #ifndef MEM_DEBUG
56 #include "mem.h"
57 #else
58 #define xfree free
59 #define xrealloc realloc
60 #define xmalloc malloc
61 #define xstrdup strdup
62 #define xcalloc calloc
63 #endif
65 #include "types.h"
67 #ifdef USE_PINENTRY
68 static pwm_t *gpwm;
69 static int gelapsed, gtimeout;
70 static gpg_error_t pinentry_command(pwm_t *pwm, char **result, const char *cmd);
71 static gpg_error_t global_error;
72 #endif
75 const char *pwmd_strerror(gpg_error_t e)
77 gpg_err_code_t code = gpg_err_code(e);
79 if (code >= GPG_ERR_USER_1 && code < gpg_err_code(EPWMD_MAX)) {
80 switch (code) {
81 case GPG_ERR_USER_1:
82 default:
83 return N_("Unknown error");
84 case GPG_ERR_USER_2:
85 return N_("No cache slots available");
86 case GPG_ERR_USER_3:
87 return N_("Recursion loop");
88 case GPG_ERR_USER_4:
89 return N_("No file is open");
90 case GPG_ERR_USER_5:
91 return N_("General LibXML error");
92 case GPG_ERR_USER_6:
93 return N_("File modified");
97 return gpg_strerror(e);
100 gpg_error_t pwmd_init()
102 #ifdef ENABLE_NLS
103 bindtextdomain("libpwmd", LOCALEDIR);
104 #endif
105 gpg_err_init();
106 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
107 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
108 return 0;
111 pwm_t *pwmd_connect(const char *path, gpg_error_t *error)
113 pwm_t *pwm = NULL;
114 char *socketpath = NULL;
115 time_t now;
116 struct passwd *pw;
117 assuan_context_t ctx;
118 int rc, n;
119 int active[2];
121 if (!path) {
122 pw = getpwuid(getuid());
123 socketpath = (char *)xmalloc(strlen(pw->pw_dir) + strlen("/.pwmd/socket") + 1);
124 sprintf(socketpath, "%s/.pwmd/socket", pw->pw_dir);
126 else
127 socketpath = xstrdup(path);
129 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
130 xfree(socketpath);
132 if (rc) {
133 *error = rc;
134 return NULL;
137 n = assuan_get_active_fds(ctx, 0, active, sizeof(active));
139 if ((pwm = (pwm_t *)xcalloc(1, sizeof(pwm_t))) == NULL) {
140 *error = gpg_error_from_errno(errno);
141 assuan_disconnect(ctx);
142 return NULL;
145 pwm->fd = n <= 0 ? -1 : dup(active[0]);
147 if (pwm->fd != -1)
148 fcntl(pwm->fd, F_SETFL, O_NONBLOCK);
150 pwm->ctx = ctx;
151 #ifdef USE_PINENTRY
152 pwm->pid = -1;
153 pwm->pinentry_tries = 3;
154 #endif
155 time(&now);
156 srandom(now);
157 *error = 0;
158 return pwm;
161 void pwmd_close(pwm_t *pwm)
163 if (!pwm)
164 return;
166 if (pwm->ctx)
167 assuan_disconnect(pwm->ctx);
169 if (pwm->password)
170 xfree(pwm->password);
172 if (pwm->title)
173 xfree(pwm->title);
175 if (pwm->desc)
176 xfree(pwm->desc);
178 if (pwm->prompt)
179 xfree(pwm->prompt);
181 if (pwm->pinentry_tty)
182 xfree(pwm->pinentry_tty);
184 if (pwm->pinentry_display)
185 xfree(pwm->pinentry_display);
187 if (pwm->pinentry_term)
188 xfree(pwm->pinentry_term);
190 if (pwm->filename)
191 xfree(pwm->filename);
193 xfree(pwm);
196 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
198 membuf_t *mem = (membuf_t *)data;
199 void *p;
201 if (!buffer)
202 return 0;
204 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
205 return 1;
207 mem->buf = p;
208 memcpy((char *)mem->buf + mem->len, buffer, len);
209 mem->len += len;
210 return 0;
213 void pwmd_free_result(void *data)
215 xfree(data);
218 static int _inquire_cb(void *data, const char *keyword)
220 pwm_t *pwm = (pwm_t *)data;
221 gpg_error_t rc = 0;
223 /* Shouldn't get this far without a callback. */
224 if (!pwm->inquire_func)
225 return GPG_ERR_INV_ARG;
227 for (;;) {
228 char *result = NULL;
229 size_t len;
230 gpg_error_t arc;
232 rc = pwm->inquire_func(pwm->inquire_data, keyword, rc, &result, &len);
233 rc = gpg_err_code(rc);
235 if (rc == GPG_ERR_EOF || !rc) {
236 if (len <= 0 || !result || !*result) {
237 rc = 0;
238 break;
241 arc = assuan_send_data(pwm->ctx, result, len);
243 if (rc == GPG_ERR_EOF) {
244 rc = arc;
245 break;
248 rc = arc;
250 else if (rc)
251 break;
254 return rc;
257 gpg_error_t pwmd_finalize(pwm_t *pwm)
259 pwm->state = ASYNC_INIT;
260 return 0;
263 gpg_error_t do_nb_command(pwm_t *pwm, const char *cmd, const char *arg)
265 char *buf;
266 gpg_error_t rc;
268 if (pwm->state != ASYNC_INIT)
269 return GPG_ERR_UNEXPECTED;
271 if (asprintf(&buf, "%s %s", cmd, arg ? arg : "") == -1) {
272 rc = gpg_error_from_errno(ENOMEM);
273 goto fail;
276 rc = assuan_write_line(pwm->ctx, buf);
277 free(buf);
279 if (!rc)
280 pwm->state = ASYNC_PROCESS;
282 fail:
283 return rc;
286 gpg_error_t pwmd_open_async(pwm_t *pwm, const char *filename)
288 if (!pwm || !filename)
289 return GPG_ERR_INV_ARG;
291 return do_nb_command(pwm, "OPEN", filename);
294 gpg_error_t pwmd_save_async(pwm_t *pwm)
296 if (!pwm)
297 return GPG_ERR_INV_ARG;
299 return do_nb_command(pwm, "SAVE", NULL);
302 static gpg_error_t parse_assuan_line(pwm_t *pwm)
304 gpg_error_t rc;
305 char *line;
306 size_t len;
308 again:
309 rc = assuan_read_line(pwm->ctx, &line, &len);
311 if (!rc) {
312 if (line[0] == 'O' && line[1] == 'K' &&
313 (line[2] == 0 || line[2] == ' ')) {
314 pwm->state = ASYNC_DONE;
316 else if (line[0] == '#') {
318 else if (line[0] == 'S' && (line[1] == 0 || line[1] == ' ')) {
319 if (pwm->status_func) {
320 pwm->status_func(pwm->status_data,
321 line[1] == 0 ? line+1 : line+2);
324 goto again;
326 else if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
327 (line[3] == 0 || line[3] == ' ')) {
328 line += 4;
329 rc = atoi(line);
330 pwm->state = ASYNC_DONE;
334 return rc;
337 pwmd_async_t pwmd_process(pwm_t *pwm, gpg_error_t *rc)
339 fd_set rfds;
340 int n;
341 struct timeval tv = {0, 0};
343 *rc = 0;
345 if (!pwm || pwm->fd < 0) {
346 *rc = GPG_ERR_INV_ARG;
347 return ASYNC_DONE;
349 else if (pwm->state == ASYNC_DONE)
350 return pwm->state;
351 else if (pwm->state == ASYNC_INIT) {
352 *rc = GPG_ERR_UNEXPECTED;
353 return ASYNC_DONE;
356 FD_ZERO(&rfds);
357 FD_SET(pwm->fd, &rfds);
358 n = select(pwm->fd+1, &rfds, NULL, NULL, &tv);
360 if (n > 0) {
361 if (FD_ISSET(pwm->fd, &rfds))
362 *rc = parse_assuan_line(pwm);
365 return pwm->state;
368 static gpg_error_t assuan_command(pwm_t *pwm, assuan_context_t ctx,
369 char **result, const char *cmd)
371 membuf_t data;
372 gpg_error_t rc;
374 data.len = 0;
375 data.buf = NULL;
377 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, _inquire_cb, pwm,
378 pwm->status_func, pwm->status_data);
380 if (rc) {
381 if (data.buf) {
382 xfree(data.buf);
383 data.buf = NULL;
386 else {
387 if (data.buf) {
388 mem_realloc_cb(&data, "", 1);
389 *result = (char *)data.buf;
393 return gpg_err_code(rc);
396 gpg_error_t pwmd_inquire(pwm_t *pwm, const char *cmd, pwmd_inquire_fn fn,
397 void *data)
399 if (!pwm || !cmd || !fn)
400 return GPG_ERR_INV_ARG;
402 pwm->inquire_func = fn;
403 pwm->inquire_data = data;
404 return assuan_command(pwm, pwm->ctx, NULL, cmd);
407 gpg_error_t pwmd_terminate_pinentry(pwm_t *pwm)
409 #ifndef USE_PINENTRY
410 return GPG_ERR_NOT_IMPLEMENTED;
411 #else
412 if (!pwm || pwm->pid == -1)
413 return GPG_ERR_INV_ARG;
415 if (kill(pwm->pid, 0) == 0) {
416 if (kill(pwm->pid, SIGTERM) == -1) {
417 if (kill(pwm->pid, SIGKILL) == -1)
418 return gpg_error_from_errno(errno);
421 pwm->pin_error = GPG_ERR_TIMEOUT;
423 else
424 return gpg_error_from_errno(errno);
426 return 0;
427 #endif
430 #ifdef USE_PINENTRY
431 static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which)
433 char *buf;
434 char tmp[ASSUAN_LINELENGTH];
435 gpg_error_t error;
437 if (!pwm->title)
438 pwm->title = xstrdup(N_("LibPWMD"));
440 if (!pwm->prompt)
441 pwm->prompt = xstrdup(N_("Password:"));
443 if (!pwm->desc && !which)
444 pwm->desc = xstrdup(N_("Enter a password."));
446 if (which == 1) {
447 snprintf(tmp, sizeof(tmp), "SETERROR %s", N_("Invalid password, please try again."));
448 buf = xstrdup(tmp);
450 else if (which == 2) {
451 snprintf(tmp, sizeof(tmp), "SETERROR %s", N_("Please type the password again for confirmation."));
452 buf = xstrdup(tmp);
454 else {
455 buf = (char *)xmalloc(strlen("SETERROR ") + strlen(pwm->desc) + 1);
456 sprintf(buf, "SETERROR %s", pwm->desc);
459 error = pinentry_command(pwm, NULL, buf);
460 xfree(buf);
462 if (error)
463 return error;
465 buf = (char *)xmalloc(strlen("SETPROMPT ") + strlen(pwm->prompt) + 1);
466 sprintf(buf, "SETPROMPT %s", pwm->prompt);
467 error = pinentry_command(pwm, NULL, buf);
468 xfree(buf);
470 if (error)
471 return error;
473 buf = (char *)xmalloc(strlen("SETDESC ") + strlen(pwm->title) + 1);
474 sprintf(buf, "SETDESC %s", pwm->title);
475 error = pinentry_command(pwm, NULL, buf);
476 xfree(buf);
477 return error;
480 static void update_pinentry_settings(pwm_t *pwm)
482 FILE *fp;
483 char buf[LINE_MAX];
484 struct passwd *pw = getpwuid(getuid());
485 char *p;
487 snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", pw->pw_dir);
489 if ((fp = fopen(buf, "r")) == NULL)
490 return;
492 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
493 char name[32], val[256];
495 if (sscanf(p, " %31[a-zA-Z] = %255s", name, val) != 2)
496 continue;
498 if (strcasecmp(name, "TTYNAME") == 0) {
499 xfree(pwm->pinentry_tty);
500 pwm->pinentry_tty = xstrdup(val);
502 else if (strcasecmp(name, "TTYTYPE") == 0) {
503 xfree(pwm->pinentry_term);
504 pwm->pinentry_term = xstrdup(val);
506 else if (strcasecmp(name, "DISPLAY") == 0) {
507 xfree(pwm->pinentry_display);
508 pwm->pinentry_display = xstrdup(val);
510 else if (strcasecmp(name, "PATH") == 0) {
511 xfree(pwm->pinentry_path);
512 pwm->pinentry_path = xstrdup(val);
516 fclose(fp);
519 static gpg_error_t launch_pinentry(pwm_t *pwm)
521 int rc;
522 assuan_context_t ctx;
523 int child_list[] = {-1};
524 char *display = getenv("DISPLAY");
525 const char *argv[6];
526 int have_display = 0;
527 char *tty = NULL;
529 update_pinentry_settings(pwm);
531 if (pwm->pinentry_display || display)
532 have_display = 1;
533 else {
534 tty = pwm->pinentry_tty ? pwm->pinentry_tty : ttyname(STDOUT_FILENO);
536 if (!tty)
537 return gpg_error_from_errno(errno);
540 if (!have_display && !tty)
541 return GPG_ERR_ENOTTY;
543 argv[0] = "pinentry";
544 argv[1] = have_display ? "--display" : "--ttyname";
545 argv[2] = have_display ? pwm->pinentry_display ? pwm->pinentry_display : display : tty;
546 argv[3] = NULL;
548 if (!have_display) {
549 argv[3] = "--ttytype";
550 argv[4] = pwm->pinentry_term ? pwm->pinentry_term : getenv("TERM");
551 argv[5] = NULL;
554 rc = assuan_pipe_connect(&ctx, pwm->pinentry_path ? pwm->pinentry_path : PINENTRY_PATH, argv, child_list);
556 if (rc)
557 return rc;
559 pwm->pid = assuan_get_pid(ctx);
560 pwm->pctx = ctx;
561 return set_pinentry_strings(pwm, 0);
564 static gpg_error_t pinentry_command(pwm_t *pwm, char **result, const char *cmd)
566 gpg_error_t n;
568 if (!pwm->pctx) {
569 n = launch_pinentry(pwm);
571 if (n)
572 return n;
575 return assuan_command(pwm, pwm->pctx, result, cmd);
578 static void pinentry_disconnect(pwm_t *pwm)
580 if (pwm->pctx)
581 assuan_disconnect(pwm->pctx);
583 pwm->pctx = NULL;
584 pwm->pid = -1;
588 * Only called from a child process.
590 static void catchsig(int sig)
592 switch (sig) {
593 case SIGALRM:
594 if (gelapsed++ >= gtimeout) {
595 global_error = pwmd_terminate_pinentry(gpwm);
597 if (!global_error)
598 global_error = GPG_ERR_TIMEOUT;
600 break;
603 alarm(1);
604 break;
605 default:
606 break;
610 static char *percent_escape(const char *atext)
612 const unsigned char *s;
613 int len = strlen(atext) * 3 + 1;
614 char *buf = (char *)xmalloc(len), *p = buf;
616 if (!buf)
617 return NULL;
619 for (s=(const unsigned char *)atext; *s; s++) {
620 if (*s < ' ') {
621 sprintf (p, "%%%02X", *s);
622 p += 3;
624 else
625 *p++ = *s;
628 *p = 0;
629 return buf;
631 #endif
633 static gpg_error_t send_command(pwm_t *pwm, char **result, const char *cmd)
635 if (!cmd)
636 return GPG_ERR_INV_ARG;
638 return assuan_command(pwm, pwm->ctx, result, cmd);
642 * Avoid sending the BYE command here. libassuan will close the file
643 * descriptor and release the assuan context. Use pwmd_close() instead.
645 gpg_error_t pwmd_command(pwm_t *pwm, char **result, const char *cmd, ...)
647 va_list ap;
648 char *buf;
649 size_t len;
650 gpg_error_t error;
652 if (!pwm || !cmd)
653 return GPG_ERR_INV_ARG;
655 *result = NULL;
656 va_start(ap, cmd);
658 * C99
660 len = vsnprintf(NULL, 0, cmd, ap);
661 buf = (char *)xmalloc(len + 1);
662 len = vsnprintf(buf, len + 1, cmd, ap);
663 va_end(ap);
664 error = send_command(pwm, result, buf);
665 xfree(buf);
666 return error;
669 #ifdef USE_PINENTRY
670 static gpg_error_t do_getpin(pwm_t *pwm, char **result)
672 if (gtimeout) {
673 signal(SIGALRM, catchsig);
674 alarm(1);
677 *result = NULL;
678 return pinentry_command(pwm, result, "GETPIN");
681 static gpg_error_t getpin(pwm_t *pwm, char **result, int *try_n, int which)
683 int pin_try = *try_n;
684 gpg_error_t error;
686 getpin_again:
687 *try_n = pin_try;
689 if (pin_try == -1) {
690 error = set_pinentry_strings(pwm, which);
692 if (error) {
693 pinentry_disconnect(pwm);
694 return error;
697 else {
698 if (pwm->pinentry_tries-1 != pin_try) {
699 error = set_pinentry_strings(pwm, 1);
701 if (error) {
702 pinentry_disconnect(pwm);
703 return error;
708 error = do_getpin(pwm, result);
711 * Since there was input cancel any timeout.
713 alarm(0);
715 if (error) {
716 if (error == GPG_ERR_ASS_CANCELED || error == ASSUAN_Canceled)
717 return GPG_ERR_ASS_CANCELED;
719 if (pin_try != -1 && pin_try--)
720 goto getpin_again;
722 if (pwm->pctx)
723 pinentry_disconnect(pwm);
725 *try_n = pin_try;
726 return error;
729 return 0;
731 #endif
733 gpg_error_t pwmd_open_nb_finalize(pwm_t *pwm, pwmd_nb_status_t *pw)
735 char *result;
736 gpg_error_t error;
738 #ifndef USE_PINENTRY
739 return GPG_ERR_NOT_IMPLEMENTED;
740 #endif
742 if (!pwm || !pw || !pw->filename[0])
743 return GPG_ERR_INV_ARG;
745 close(pw->fd);
747 if (pw->error) {
748 error = pw->error;
749 goto fail;
752 error = pwmd_command(pwm, &result, "ISCACHED %s", pw->filename);
754 if (error)
755 goto fail;
757 if (pwm->filename)
758 xfree(pwm->filename);
760 pwm->filename = xstrdup(pw->filename);
761 memset(pw, 0, sizeof(pwmd_nb_status_t));
762 return 0;
764 fail:
765 memset(pw, 0, sizeof(pwmd_nb_status_t));
766 return error;
769 static gpg_error_t do_open_command(pwm_t *pwm, const char *filename, char *password)
771 char buf[ASSUAN_LINELENGTH];
772 gpg_error_t error;
773 char *result = NULL;
775 snprintf(buf, sizeof(buf), "OPEN %s %s", filename, password ? password : "");
776 error = send_command(pwm, &result, buf);
777 memset(buf, 0, sizeof(buf));
779 if (error && result)
780 xfree(result);
782 return error;
785 static int do_pwmd_open(pwm_t *pwm, gpg_error_t *error, const char *filename,
786 int nb, int timeout)
788 char *result = NULL;
789 char *password = NULL;
790 char path[PATH_MAX];
791 #ifdef USE_PINENTRY
792 int pin_try;
793 #endif
795 if (!pwm || !filename || !*filename) {
796 *error = GPG_ERR_INV_ARG;
797 return nb ? -1 : 1;
800 #ifdef USE_PINENTRY
801 pin_try = pwm->pinentry_tries - 1;
802 #endif
805 * Avoid calling pinentry if the password is cached on the server or if
806 * this is a new file.
808 *error = pwmd_command(pwm, &result, "GETCONFIG data_directory");
810 if (*error)
811 return nb ? -1 : 1;
813 snprintf(path, sizeof(path), "%s/%s", result, filename);
814 pwmd_free_result(result);
816 if (access(path, R_OK) == -1) {
817 if (errno == ENOENT)
818 goto gotpassword;
820 *error = gpg_error_from_errno(errno);
821 return nb ? -1 : 1;
824 *error = pwmd_command(pwm, &result, "ISCACHED %s", filename);
826 if (*error == EPWMD_CACHE_NOT_FOUND) {
827 if (pwm->passfunc) {
828 password = pwm->passfunc(pwm, pwm->passdata);
829 goto gotpassword;
832 if (*error == EPWMD_CACHE_NOT_FOUND) {
833 #ifdef USE_PINENTRY
835 * Get the password from pinentry.
837 if (pwm->use_pinentry) {
839 * Nonblocking is wanted. fork() then return a file descriptor
840 * that the client can use to read() from.
842 if (nb) {
843 int p[2];
844 pid_t pid;
845 pwmd_nb_status_t pw;
847 if (pipe(p) == -1) {
848 *error = gpg_error_from_syserror();
849 return -1;
852 pid = fork();
854 switch (pid) {
855 case 0:
856 close(p[0]);
857 strncpy(pw.filename, filename, sizeof(pw.filename));
858 pw.filename[sizeof(pw.filename)-1] = 0;
859 pw.fd = p[0];
861 if (timeout > 0) {
862 gpwm = pwm;
863 gtimeout = timeout;
864 gelapsed = 0;
867 getpin_nb_again:
868 *error = getpin(pwm, &password, &pin_try, 0);
870 if (*error) {
871 getpin_nb_fail:
872 if (pwm->pctx)
873 pinentry_disconnect(pwm);
875 if (gtimeout && gelapsed >= gtimeout)
876 *error = GPG_ERR_TIMEOUT;
878 pw.error = *error;
879 write(p[1], &pw, sizeof(pw));
880 close(p[1]);
881 _exit(1);
885 * Don't count the time it takes to open the file
886 * which may have many iterations.
888 signal(SIGALRM, SIG_DFL);
889 *error = do_open_command(pwm, filename, password);
891 if (timeout)
892 signal(SIGALRM, catchsig);
894 if (pwm->pctx && *error == EPWMD_BADKEY) {
895 if (pin_try-- > 0)
896 goto getpin_nb_again;
898 goto getpin_nb_fail;
901 pinentry_disconnect(pwm);
902 pw.error = 0;
903 write(p[1], &pw, sizeof(pw));
904 close(p[1]);
905 _exit(0);
906 break;
907 case -1:
908 *error = gpg_error_from_syserror();
909 close(p[0]);
910 close(p[1]);
911 return -1;
912 default:
913 break;
916 close(p[1]);
917 return p[0];
920 getpin_again:
921 *error = getpin(pwm, &password, &pin_try, 1);
923 if (*error) {
924 if (pwm->pctx)
925 pinentry_disconnect(pwm);
927 if (pwm->pin_error) {
928 *error = pwm->pin_error;
929 pwm->pin_error = 0;
932 return 1;
935 else {
936 #endif
938 * Not using pinentry and the file was not found
939 * in the cache.
941 #if 0
942 if (pwm->password == NULL) {
943 *error = EPWMD_KEY;
944 return 1;
946 #endif
948 password = pwm->password;
949 #ifdef USE_PINENTRY
951 #endif
954 else if (*error)
955 return nb ? -1 : 1;
957 gotpassword:
958 *error = do_open_command(pwm, filename, password);
961 * Keep the user defined password set with pwmd_setopt(). The password may
962 * be needed later (pwmd_save()) depending on the pwmd file cache settings.
964 if (password && password != pwm->password)
965 xfree(password);
967 #ifdef USE_PINENTRY
968 if (pwm->pctx && *error == EPWMD_BADKEY) {
969 if (pin_try-- > 0)
970 goto getpin_again;
972 pinentry_disconnect(pwm);
973 return nb ? -1 : 1;
975 else if (pwm->pctx)
976 pinentry_disconnect(pwm);
977 #endif
979 if (!*error) {
980 if (pwm->filename)
981 xfree(pwm->filename);
983 pwm->filename = xstrdup(filename);
987 * The file is cached or the file is a new file.
989 if (nb)
990 return *error ? -1 : -2;
992 return *error ? 1 : 0;
995 gpg_error_t pwmd_open(pwm_t *pwm, const char *filename)
997 gpg_error_t error;
999 do_pwmd_open(pwm, &error, filename, 0, 0);
1000 return error;
1003 int pwmd_open_nb(pwm_t *pwm, gpg_error_t *error, const char *filename,
1004 int timeout)
1006 #ifndef USE_PINENTRY
1007 *error = GPG_ERR_NOT_IMPLEMENTED;
1008 return -1;
1009 #else
1010 return do_pwmd_open(pwm, error, filename, 1, timeout);
1011 #endif
1014 #ifdef USE_PINENTRY
1015 static gpg_error_t do_save_getpin(pwm_t *pwm, char **password)
1017 int confirm = 0;
1018 gpg_error_t error;
1019 char *result = NULL;
1020 int pin_try = -1;
1022 again:
1023 error = getpin(pwm, &result, &pin_try, confirm ? 2 : 0);
1025 if (error) {
1026 if (pwm->pctx)
1027 pinentry_disconnect(pwm);
1029 if (*password)
1030 xfree(*password);
1032 return error;
1035 if (!confirm++) {
1036 *password = result;
1037 goto again;
1040 if (strcmp(*password, result)) {
1041 xfree(*password);
1042 xfree(result);
1043 pinentry_disconnect(pwm);
1044 error = EPWMD_BADKEY;
1045 return error;
1048 xfree(result);
1049 pinentry_disconnect(pwm);
1050 return 0;
1052 #endif
1054 static gpg_error_t do_save_command(pwm_t *pwm, char *password)
1056 char buf[ASSUAN_LINELENGTH];
1057 gpg_error_t error;
1058 char *result = NULL;
1060 snprintf(buf, sizeof(buf), "SAVE %s", password ? password : "");
1061 error = send_command(pwm, &result, buf);
1062 memset(&buf, 0, sizeof(buf));
1064 if (error && result)
1065 xfree(result);
1067 return error;
1070 gpg_error_t pwmd_save_nb_finalize(pwm_t *pwm, pwmd_nb_status_t *pw)
1072 gpg_error_t error;
1074 #ifndef USE_PINENTRY
1075 return GPG_ERR_NOT_IMPLEMENTED;
1076 #endif
1078 if (!pwm || !pw || !pw->filename[0])
1079 return GPG_ERR_INV_ARG;
1081 close(pw->fd);
1083 if (pw->error) {
1084 error = pw->error;
1085 memset(pw, 0, sizeof(pwmd_nb_status_t));
1086 return error;
1089 memset(pw, 0, sizeof(pwmd_nb_status_t));
1090 return 0;
1093 static int do_pwmd_save(pwm_t *pwm, gpg_error_t *error, int nb)
1095 char *result = NULL;
1096 char *password = NULL;
1098 if (!pwm) {
1099 *error = GPG_ERR_INV_ARG;
1100 return nb ? -1 : 1;
1103 if (pwm->use_pinentry || pwm->passfunc) {
1104 *error = pwmd_command(pwm, &result, "ISCACHED %s", pwm->filename);
1106 if (*error == EPWMD_CACHE_NOT_FOUND) {
1107 #ifdef USE_PINENTRY
1108 if (pwm->use_pinentry) {
1109 if (nb) {
1110 int p[2];
1111 pid_t pid;
1112 pwmd_nb_status_t pw;
1114 if (pipe(p) == -1) {
1115 *error = gpg_error_from_syserror();
1116 return -1;
1119 pid = fork();
1121 switch (pid) {
1122 case 0:
1123 close(p[0]);
1124 strncpy(pw.filename, pwm->filename, sizeof(pw.filename));
1125 pw.filename[sizeof(pw.filename)-1] = 0;
1126 pw.fd = p[0];
1128 do {
1129 password = NULL;
1130 *error = do_save_getpin(pwm, &password);
1131 } while (*error == EPWMD_BADKEY);
1133 if (*error) {
1134 if (pwm->pctx)
1135 pinentry_disconnect(pwm);
1137 pw.error = *error;
1138 write(p[1], &pw, sizeof(pw));
1139 close(p[1]);
1140 _exit(1);
1143 *error = do_save_command(pwm, password);
1144 pinentry_disconnect(pwm);
1145 pw.error = *error;
1146 write(p[1], &pw, sizeof(pw));
1147 close(p[1]);
1148 _exit(0);
1149 break;
1150 case -1:
1151 *error = gpg_error_from_syserror();
1152 close(p[0]);
1153 close(p[1]);
1154 return -1;
1155 default:
1156 break;
1159 close(p[1]);
1160 return p[0];
1163 *error = do_save_getpin(pwm, &password);
1165 if (*error)
1166 return 1;
1168 else {
1169 #endif
1170 if (pwm->passfunc)
1171 password = (*pwm->passfunc)(pwm, pwm->passdata);
1172 #ifdef USE_PINENTRY
1174 #endif
1176 else {
1177 if (*error)
1178 return nb ? -1 : 1;
1181 else
1182 password = pwm->password;
1184 *error = do_save_command(pwm, password);
1186 if (password && password != pwm->password)
1187 xfree(password);
1189 if (nb)
1190 return *error ? -1 : -2;
1192 return *error ? 1 : 0;
1195 int pwmd_save_nb(pwm_t *pwm, gpg_error_t *error)
1197 #ifndef USE_PINENTRY
1198 *error = GPG_ERR_NOT_IMPLEMENTED;
1199 return -1;
1200 #else
1201 return do_pwmd_save(pwm, error, 1);
1202 #endif
1205 gpg_error_t pwmd_save(pwm_t *pwm)
1207 gpg_error_t error;
1209 do_pwmd_save(pwm, &error, 0);
1210 return error;
1213 gpg_error_t pwmd_setopt(pwm_t *pwm, pwmd_option_t opt, ...)
1215 va_list ap;
1216 #ifdef USE_PINENTRY
1217 int n = va_arg(ap, int);
1218 char *result;
1219 #endif
1220 char *arg1;
1221 gpg_error_t error = 0;
1223 if (!pwm)
1224 return GPG_ERR_INV_ARG;
1226 va_start(ap, opt);
1228 switch (opt) {
1229 case PWMD_OPTION_STATUS_FUNC:
1230 pwm->status_func = va_arg(ap, pwmd_status_fn);
1231 break;
1232 case PWMD_OPTION_STATUS_DATA:
1233 pwm->status_data = va_arg(ap, void *);
1234 break;
1235 case PWMD_OPTION_PASSWORD_FUNC:
1236 pwm->passfunc = va_arg(ap, pwmd_password_fn);
1237 break;
1238 case PWMD_OPTION_PASSWORD_DATA:
1239 pwm->passdata = va_arg(ap, void *);
1240 break;
1241 case PWMD_OPTION_PASSWORD:
1242 arg1 = va_arg(ap, char *);
1244 if (pwm->password)
1245 xfree(pwm->password);
1247 pwm->password = xstrdup(arg1);
1248 break;
1249 #ifdef USE_PINENTRY
1250 case PWMD_OPTION_PINENTRY:
1251 n = va_arg(ap, int);
1253 if (n != 0 && n != 1) {
1254 va_end(ap);
1255 error = GPG_ERR_INV_VALUE;
1257 else {
1258 pwm->use_pinentry = n;
1259 error = pwmd_command(pwm, &result, "OPTION PINENTRY=%i",
1260 !pwm->use_pinentry);
1262 break;
1263 case PWMD_OPTION_PINENTRY_TRIES:
1264 n = va_arg(ap, int);
1266 if (n <= 0) {
1267 va_end(ap);
1268 error = GPG_ERR_INV_VALUE;
1270 else
1271 pwm->pinentry_tries = n;
1272 break;
1273 case PWMD_OPTION_PINENTRY_PATH:
1274 if (pwm->pinentry_path)
1275 xfree(pwm->pinentry_path);
1277 pwm->pinentry_path = xstrdup(va_arg(ap, char *));
1278 break;
1279 case PWMD_OPTION_PINENTRY_TTY:
1280 if (pwm->pinentry_tty)
1281 xfree(pwm->pinentry_tty);
1283 pwm->pinentry_tty = xstrdup(va_arg(ap, char *));
1284 break;
1285 case PWMD_OPTION_PINENTRY_DISPLAY:
1286 if (pwm->pinentry_display)
1287 xfree(pwm->pinentry_display);
1289 pwm->pinentry_display = xstrdup(va_arg(ap, char *));
1290 break;
1291 case PWMD_OPTION_PINENTRY_TERM:
1292 if (pwm->pinentry_term)
1293 xfree(pwm->pinentry_term);
1295 pwm->pinentry_term = xstrdup(va_arg(ap, char *));
1296 break;
1297 case PWMD_OPTION_PINENTRY_TITLE:
1298 if (pwm->title)
1299 xfree(pwm->title);
1300 pwm->title = percent_escape(va_arg(ap, char *));
1301 break;
1302 case PWMD_OPTION_PINENTRY_PROMPT:
1303 if (pwm->prompt)
1304 xfree(pwm->prompt);
1305 pwm->prompt = percent_escape(va_arg(ap, char *));
1306 break;
1307 case PWMD_OPTION_PINENTRY_DESC:
1308 if (pwm->desc)
1309 xfree(pwm->desc);
1310 pwm->desc = percent_escape(va_arg(ap, char *));
1311 break;
1312 #else
1313 case PWMD_OPTION_PINENTRY:
1314 case PWMD_OPTION_PINENTRY_TRIES:
1315 case PWMD_OPTION_PINENTRY_PATH:
1316 case PWMD_OPTION_PINENTRY_TTY:
1317 case PWMD_OPTION_PINENTRY_DISPLAY:
1318 case PWMD_OPTION_PINENTRY_TERM:
1319 case PWMD_OPTION_PINENTRY_TITLE:
1320 case PWMD_OPTION_PINENTRY_PROMPT:
1321 case PWMD_OPTION_PINENTRY_DESC:
1322 error = GPG_ERR_NOT_IMPLEMENTED;
1323 break;
1324 #endif
1325 default:
1326 error = GPG_ERR_NOT_IMPLEMENTED;
1327 break;
1330 va_end(ap);
1331 return error;