Return -1 if the file is cached but there was an error or -2 if the
[libpwmd.git] / libpwmd.c
blob803288e756f62603c6bac927b548b46374f79210
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 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 <libpwmd.h>
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
41 #ifdef HAVE_ASSUAN_H
42 #include <assuan.h>
43 #endif
45 #ifdef HAVE_SETLOCALE
46 #include <locale.h>
47 #endif
49 #include "mem.h"
50 #include "asshelp.h"
52 #ifdef USE_PINENTRY
53 #define PINENTRY_PATH "/usr/local/bin/pinentry"
54 static gpg_error_t pinentry_command(pwm_t *pwm, char **result, const char *cmd);
55 #endif
57 struct pwm_s {
58 assuan_context_t ctx;
59 #ifdef USE_PINENTRY
60 assuan_context_t pctx; /* pinentry */
61 #endif
62 int use_pinentry;
63 int pinentry_tries;
64 char *pinentry_path;
65 char *pinentry_tty;
66 char *pinentry_term;
67 char *pinentry_display;
68 char *title;
69 char *prompt;
70 char *desc;
71 char *password;
72 char *filename;
73 pwmd_password_fn passfunc;
74 void *passdata;
75 pwmd_status_fn status_func;
76 void *status_data;
79 struct pwmd_nb_status_s {
80 char filename[FILENAME_MAX];
81 gpg_error_t error;
84 typedef struct {
85 size_t len;
86 void *buf;
87 } membuf_t;
89 struct inquire_s {
90 assuan_context_t ctx;
91 const char *buf;
92 size_t len;
95 const char *pwmd_strerror(gpg_error_t pwmd_errno)
97 gpg_err_code_t code = gpg_err_code(pwmd_errno);
99 if (code >= GPG_ERR_USER_1 && code < gpg_err_code(EPWMD_MAX)) {
100 switch (code) {
101 case GPG_ERR_USER_1:
102 default:
103 return "Unknown error";
104 case GPG_ERR_USER_2:
105 return "No cache slots available";
106 case GPG_ERR_USER_3:
107 return "Element not found";
108 case GPG_ERR_USER_4:
109 return "Trailing element";
110 case GPG_ERR_USER_5:
111 return "Invalid character in element";
112 case GPG_ERR_USER_6:
113 return "Empty";
114 case GPG_ERR_USER_7:
115 return "Will not overwrite existing account";
116 case GPG_ERR_USER_8:
117 return "File not found";
118 case GPG_ERR_USER_9:
119 return "No file is open";
120 case GPG_ERR_USER_10:
121 return "General LibXML error";
122 case GPG_ERR_USER_11:
123 return "File not found in cache";
124 case GPG_ERR_USER_12:
125 return "Attribute not found";
126 case GPG_ERR_USER_13:
127 return "Invalid filename or link";
128 case GPG_ERR_USER_14:
129 return "File modified";
133 return gpg_strerror(pwmd_errno);
136 pwmd_error_t pwmd_init()
138 gpg_err_init();
139 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
140 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
142 return PWMD_OK;
145 pwm_t *pwmd_connect(const char *path, gpg_error_t *error)
147 pwm_t *pwm = NULL;
148 char *socketpath = NULL;
149 time_t now;
150 struct passwd *pw;
151 assuan_context_t ctx;
152 int rc;
154 if (!path) {
155 pw = getpwuid(getuid());
156 socketpath = (char *)xmalloc(strlen(pw->pw_dir) + strlen("/.pwmd/socket") + 1);
157 sprintf(socketpath, "%s/.pwmd/socket", pw->pw_dir);
159 else
160 socketpath = xstrdup(path);
162 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
163 xfree(socketpath);
165 if (rc) {
166 *error = rc;
167 return NULL;
170 if ((pwm = (pwm_t *)xcalloc(1, sizeof(pwm_t))) == NULL) {
171 *error = gpg_error_from_errno(errno);
172 assuan_disconnect(ctx);
173 return NULL;
176 pwm->ctx = ctx;
177 #ifdef USE_PINENTRY
178 pwm->pinentry_tries = 3;
179 #endif
180 time(&now);
181 srandom(now);
182 return pwm;
185 void pwmd_close(pwm_t *pwm)
187 if (!pwm)
188 return;
190 if (pwm->ctx)
191 assuan_disconnect(pwm->ctx);
193 if (pwm->password)
194 xfree(pwm->password);
196 if (pwm->title)
197 xfree(pwm->title);
199 if (pwm->desc)
200 xfree(pwm->desc);
202 if (pwm->prompt)
203 xfree(pwm->prompt);
205 if (pwm->pinentry_tty)
206 xfree(pwm->pinentry_tty);
208 if (pwm->pinentry_display)
209 xfree(pwm->pinentry_display);
211 if (pwm->pinentry_term)
212 xfree(pwm->pinentry_term);
214 if (pwm->filename)
215 xfree(pwm->filename);
217 xfree(pwm);
220 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
222 membuf_t *mem = (membuf_t *)data;
223 void *p;
225 if (!buffer)
226 return 0;
228 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
229 return 1;
231 mem->buf = p;
232 memcpy((char *)mem->buf + mem->len, buffer, len);
233 mem->len += len;
234 return 0;
237 static int inquire_cb(void *data, const char *keyword)
239 struct inquire_s *inquire = (struct inquire_s *)data;
241 return assuan_send_data(inquire->ctx, inquire->buf, inquire->len);
244 void pwmd_free_result(void *data)
246 xfree(data);
249 static gpg_error_t assuan_command(pwm_t *pwm, assuan_context_t ctx,
250 char **result, const char *cmd)
252 membuf_t data;
253 gpg_error_t rc;
255 data.len = 0;
256 data.buf = NULL;
259 * This is needed because assuan only accepts 1000 byte command strings.
260 * If the line is more than this the command will fail. So we use an
261 * INQUIRE on the server which waits for an END that assuan_transact()
262 * fulfills.
264 * Other commands shouldn't need the INQUIRE. Let me know if you have an
265 * element path that's greater than 1000 bytes and I'll fix it.
267 if (strncasecmp(cmd, "STORE", 5) == 0) {
268 const char *p = cmd + 5;
269 struct inquire_s *inq = (struct inquire_s *)xmalloc(sizeof(struct inquire_s));
271 if (*p == ' ')
272 p++;
274 inq->ctx = ctx;
275 inq->buf = p;
276 inq->len = strlen(p);
277 rc = assuan_transact(ctx, "STORE", mem_realloc_cb, &data, inquire_cb,
278 inq, pwm->status_func, pwm->status_data);
279 xfree(inq);
281 else {
282 #ifdef USE_PINENTRY
284 * Ignore any status callback function for pinentry.
286 if (ctx == pwm->pctx)
287 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, NULL, NULL, NULL, NULL);
288 else
289 #endif
290 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, NULL, NULL,
291 pwm->status_func, pwm->status_data);
294 if (rc) {
295 if (data.buf) {
296 xfree(data.buf);
297 data.buf = NULL;
300 else {
301 if (data.buf) {
302 mem_realloc_cb(&data, "", 1);
303 *result = (char *)data.buf;
307 return gpg_err_code(rc);
310 #ifdef USE_PINENTRY
311 static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which)
313 char *buf;
314 gpg_error_t error;
316 if (!pwm->title)
317 pwm->title = xstrdup("LibPWMD");
319 if (!pwm->prompt)
320 pwm->prompt = xstrdup("Password:");
322 if (!pwm->desc && !which)
323 pwm->desc = xstrdup("Enter a password.");
325 if (which == 1)
326 buf = xstrdup("SETERROR Invalid password, please try again.");
327 else if (which == 2)
328 buf = xstrdup("SETERROR Please type the password again for confirmation.");
329 else {
330 buf = (char *)xmalloc(strlen("SETERROR ") + strlen(pwm->desc) + 1);
331 sprintf(buf, "SETERROR %s", pwm->desc);
334 error = pinentry_command(pwm, NULL, buf);
335 xfree(buf);
337 if (error)
338 return error;
340 buf = (char *)xmalloc(strlen("SETPROMPT ") + strlen(pwm->prompt) + 1);
341 sprintf(buf, "SETPROMPT %s", pwm->prompt);
342 error = pinentry_command(pwm, NULL, buf);
343 xfree(buf);
345 if (error)
346 return error;
348 buf = (char *)xmalloc(strlen("SETDESC ") + strlen(pwm->title) + 1);
349 sprintf(buf, "SETDESC %s", pwm->title);
350 error = pinentry_command(pwm, NULL, buf);
351 xfree(buf);
352 return error;
355 static gpg_error_t launch_pinentry(pwm_t *pwm)
357 int rc;
358 assuan_context_t ctx;
359 int child_list[] = {-1};
360 char *display = getenv("DISPLAY");
361 const char *argv[6];
362 int have_display = 0;
363 char *tty = NULL;
365 if (pwm->pinentry_display || display)
366 have_display = 1;
367 else {
368 tty = pwm->pinentry_tty ? pwm->pinentry_tty : ttyname(STDOUT_FILENO);
370 if (!tty)
371 return gpg_error_from_errno(errno);
374 if (!display && !tty)
375 return GPG_ERR_ENOTTY;
377 argv[0] = "pinentry";
378 argv[1] = have_display ? "--display" : "--ttyname";
379 argv[2] = have_display ? pwm->pinentry_display ? pwm->pinentry_display : display : tty;
380 argv[3] = NULL;
382 if (!have_display) {
383 argv[3] = "--ttytype";
384 argv[4] = pwm->pinentry_term ? pwm->pinentry_term : getenv("TERM");
385 argv[5] = NULL;
388 rc = assuan_pipe_connect(&ctx, pwm->pinentry_path ? pwm->pinentry_path : PINENTRY_PATH, argv, child_list);
390 if (rc)
391 return rc;
393 pwm->pctx = ctx;
394 return set_pinentry_strings(pwm, 0);
397 static gpg_error_t pinentry_command(pwm_t *pwm, char **result, const char *cmd)
399 gpg_error_t n;
401 if (!pwm->pctx) {
402 n = launch_pinentry(pwm);
404 if (n)
405 return n;
408 return assuan_command(pwm, pwm->pctx, result, cmd);
411 static void pinentry_disconnect(pwm_t *pwm)
413 assuan_disconnect(pwm->pctx);
414 pwm->pctx = NULL;
417 static char *percent_escape(const char *atext)
419 const unsigned char *s;
420 int len = strlen(atext) * 3 + 1;
421 char *buf = (char *)xmalloc(len), *p = buf;
423 if (!buf)
424 return NULL;
426 for (s=(const unsigned char *)atext; *s; s++) {
427 if (*s < ' ') {
428 sprintf (p, "%%%02X", *s);
429 p += 3;
431 else
432 *p++ = *s;
435 *p = 0;
436 return buf;
438 #endif
440 static gpg_error_t send_command(pwm_t *pwm, char **result, const char *cmd)
442 if (!cmd)
443 return EPWMD_ERROR;
445 return assuan_command(pwm, pwm->ctx, result, cmd);
449 * Avoid sending the BYE command here. libassuan will close the file
450 * descriptor and release the assuan context. Use pwmd_close() instead.
452 pwmd_error_t pwmd_command(pwm_t *pwm, char **result, gpg_error_t *error, const char *cmd, ...)
454 va_list ap;
455 char *buf;
456 size_t len;
458 if (!pwm)
459 return PWMD_ERROR;
461 if (!cmd) {
462 *error = EPWMD_COMMAND_SYNTAX;
463 return PWMD_ERROR;
466 *result = NULL;
467 *error = EPWMD_ERROR;
469 va_start(ap, cmd);
471 * C99
473 len = vsnprintf(NULL, 0, cmd, ap);
474 buf = (char *)xmalloc(len + 1);
475 len = vsnprintf(buf, len + 1, cmd, ap);
476 va_end(ap);
477 *error = send_command(pwm, result, buf);
478 xfree(buf);
479 return *error ? PWMD_ERROR : PWMD_OK;
482 #ifdef USE_PINENTRY
483 static gpg_error_t do_getpin(pwm_t *pwm, char **result)
485 gpg_error_t error;
487 *result = NULL;
488 error = pinentry_command(pwm, result, "GETPIN");
490 if (error == GPG_ERR_ASS_CANCELED)
491 return error;
493 if (!*result)
494 return EPWMD_KEY;
496 return 0;
499 static pwmd_error_t getpin(pwm_t *pwm, char **result, gpg_error_t *error,
500 int *try, int which)
502 int pin_try = *try;
504 getpin_again:
505 *try = pin_try;
507 if (pin_try == -1) {
508 *error = set_pinentry_strings(pwm, which);
510 if (*error) {
511 pinentry_disconnect(pwm);
512 return PWMD_ERROR;
515 else {
516 if (pwm->pinentry_tries-1 != pin_try) {
517 *error = set_pinentry_strings(pwm, 1);
519 if (*error) {
520 pinentry_disconnect(pwm);
521 return PWMD_ERROR;
526 *error = do_getpin(pwm, result);
528 if (*error) {
529 if (pin_try != -1 && pin_try-- && *error == EPWMD_KEY)
530 goto getpin_again;
532 if (pwm->pctx)
533 pinentry_disconnect(pwm);
535 *try = pin_try;
536 return PWMD_ERROR;
539 return PWMD_OK;
542 pwmd_error_t pwmd_open_nb_finalize(pwm_t *pwm, gpg_error_t *error,
543 pwmd_nb_status_t *pw)
545 char *result;
547 if (!pwm || !pw || !pw->filename[0])
548 return PWMD_ERROR;
550 if (pw->error) {
551 *error = pw->error;
552 goto fail;
555 if (pwmd_command(pwm, &result, error, "ISCACHED %s", pw->filename) != PWMD_OK)
556 goto fail;
558 if (pwm->filename)
559 xfree(pwm->filename);
561 pwm->filename = xstrdup(pw->filename);
562 memset(pw, 0, sizeof(pwmd_nb_status_t));
563 return PWMD_OK;
565 fail:
566 memset(pw, 0, sizeof(pwmd_nb_status_t));
567 return PWMD_ERROR;
569 #endif
571 static gpg_error_t do_open_command(pwm_t *pwm, const char *filename, char *password)
573 char buf[1000];
574 gpg_error_t error;
576 snprintf(buf, sizeof(buf), "OPEN %s %s", filename, password ? password : "");
577 error = send_command(pwm, NULL, buf);
578 memset(&buf, 0, sizeof(buf));
579 xfree(password);
580 return error;
583 static int do_pwmd_open(pwm_t *pwm, gpg_error_t *error, const char *filename,
584 int nb)
586 char *result = NULL;
587 char *password = NULL;
588 #ifdef USE_PINENTRY
589 int pin_try = pwm->pinentry_tries - 1;
590 #endif
592 if (!pwm || !filename || !*filename) {
593 *error = EPWMD_ERROR;
594 return PWMD_ERROR;
598 * Avoid calling pinentry if the password is cached on the server.
600 pwmd_command(pwm, &result, error, "ISCACHED %s", filename);
602 if (*error == EPWMD_CACHE_NOT_FOUND) {
603 if (pwm->passfunc) {
604 password = pwm->passfunc(pwm, pwm->passdata);
606 if (!password || !*password) {
607 *error = EPWMD_KEY;
608 return PWMD_ERROR;
611 password = xstrdup(password);
612 goto gotpassword;
615 if (*error == EPWMD_CACHE_NOT_FOUND) {
616 #ifdef USE_PINENTRY
618 * Get the password from pinentry.
620 if (pwm->use_pinentry) {
622 * Nonblocking is wanted. fork() then return a file descriptor
623 * that the client can use to read() from.
625 if (nb) {
626 int p[2];
627 pid_t pid;
628 pwmd_nb_status_t pw;
630 if (pipe(p) == -1) {
631 *error = gpg_error_from_syserror();
632 return -1;
635 pid = fork();
637 switch (pid) {
638 case 0:
639 close(p[0]);
640 strncpy(pw.filename, filename, sizeof(pw.filename));
641 getpin_nb_again:
642 getpin(pwm, &password, error, &pin_try, 0);
644 if (*error) {
645 getpin_nb_fail:
646 if (pwm->pctx)
647 pinentry_disconnect(pwm);
649 pw.error = *error;
650 write(p[1], &pw, sizeof(pw));
651 close(p[1]);
652 _exit(1);
655 *error = do_open_command(pwm, filename, password);
657 if (pwm->pctx && *error == EPWMD_BADKEY) {
658 if (pin_try-- > 0)
659 goto getpin_nb_again;
661 goto getpin_nb_fail;
664 pinentry_disconnect(pwm);
665 pw.error = 0;
666 write(p[1], &pw, sizeof(pw));
667 close(p[1]);
668 _exit(0);
669 break;
670 case -1:
671 *error = gpg_error_from_syserror();
672 close(p[0]);
673 close(p[1]);
674 return -1;
675 default:
676 break;
679 close(p[1]);
680 return p[0];
683 getpin_again:
684 getpin(pwm, &password, error, &pin_try, 1);
686 if (*error) {
687 if (pwm->pctx)
688 pinentry_disconnect(pwm);
690 return PWMD_ERROR;
693 else {
694 #endif
696 * Not using pinentry and the file was not found
697 * in the cache.
699 if (pwm->password == NULL) {
700 *error = EPWMD_KEY;
701 return PWMD_ERROR;
704 password = pwm->password;
705 #ifdef USE_PINENTRY
707 #endif
710 else if (*error && *error != EPWMD_FILE_NOT_FOUND)
711 return PWMD_ERROR;
713 gotpassword:
714 *error = do_open_command(pwm, filename, password);
716 #ifdef USE_PINENTRY
717 if (pwm->pctx && *error == EPWMD_BADKEY) {
718 if (pin_try-- > 0)
719 goto getpin_again;
721 pinentry_disconnect(pwm);
722 return PWMD_ERROR;
724 #endif
726 if (!pwm->use_pinentry && pwm->password)
727 pwm->password = NULL;
729 if (!*error) {
730 if (pwm->filename)
731 xfree(pwm->filename);
733 pwm->filename = xstrdup(filename);
737 * The file is cached or the file is a new file.
739 if (nb)
740 return *error ? -1 : -2;
742 return *error ? PWMD_ERROR : PWMD_OK;
745 pwmd_error_t pwmd_open(pwm_t *pwm, gpg_error_t *error, const char *filename)
747 return (pwmd_error_t)do_pwmd_open(pwm, error, filename, 0);
750 int pwmd_open_nb(pwm_t *pwm, gpg_error_t *error, const char *filename)
752 #ifndef USE_PINENTRY
753 *error = GPG_ERR_NOT_IMPLEMENTED;
754 return -1;
755 #else
756 return do_pwmd_open(pwm, error, filename, 1);
757 #endif
760 #ifdef USE_PINENTRY
761 static gpg_error_t do_save_getpin(pwm_t *pwm, char **password)
763 int confirm = 0;
764 gpg_error_t error;
765 char *result = NULL;
766 int pin_try = -1;
768 again:
769 getpin(pwm, &result, &error, &pin_try, confirm ? 2 : 0);
771 if (error) {
772 if (pwm->pctx)
773 pinentry_disconnect(pwm);
775 if (*password)
776 xfree(*password);
778 return error;
781 if (!confirm++) {
782 *password = result;
783 goto again;
786 if (strcmp(*password, result)) {
787 xfree(*password);
788 xfree(result);
789 pinentry_disconnect(pwm);
790 error = EPWMD_BADKEY;
791 return error;
794 xfree(result);
795 pinentry_disconnect(pwm);
796 return 0;
798 #endif
800 static gpg_error_t do_save_command(pwm_t *pwm, char *password)
802 char buf[ASSUAN_LINELENGTH];
803 gpg_error_t error;
805 snprintf(buf, sizeof(buf), "SAVE %s", password ? password : "");
806 error = send_command(pwm, NULL, buf);
807 memset(&buf, 0, sizeof(buf));
808 xfree(password);
809 pwm->password = NULL;
810 return error;
813 pwmd_error_t pwmd_save_nb_finalize(pwm_t *pwm, gpg_error_t *error,
814 pwmd_nb_status_t *pw)
816 if (!pwm || !pw || !pw->filename[0])
817 return PWMD_ERROR;
819 if (pw->error) {
820 *error = pw->error;
821 memset(pw, 0, sizeof(pwmd_nb_status_t));
822 return PWMD_ERROR;
825 memset(pw, 0, sizeof(pwmd_nb_status_t));
826 return PWMD_OK;
829 static int do_pwmd_save(pwm_t *pwm, gpg_error_t *error, int nb)
831 char *result = NULL;
832 char *password = NULL;
834 if (!pwm)
835 return PWMD_ERROR;
837 if (pwm->use_pinentry || pwm->passfunc) {
838 pwmd_command(pwm, &result, error, "ISCACHED %s", pwm->filename);
840 if (*error == EPWMD_CACHE_NOT_FOUND) {
841 #ifdef USE_PINENTRY
842 if (pwm->use_pinentry) {
843 if (nb) {
844 int p[2];
845 pid_t pid;
846 pwmd_nb_status_t pw;
848 if (pipe(p) == -1) {
849 *error = gpg_error_from_syserror();
850 return -1;
853 pid = fork();
855 switch (pid) {
856 case 0:
857 close(p[0]);
858 strncpy(pw.filename, pwm->filename, sizeof(pw.filename));
860 do {
861 password = NULL;
862 *error = do_save_getpin(pwm, &password);
863 } while (*error == EPWMD_KEY || *error == EPWMD_BADKEY);
865 if (*error) {
866 if (pwm->pctx)
867 pinentry_disconnect(pwm);
869 pw.error = *error;
870 write(p[1], &pw, sizeof(pw));
871 close(p[1]);
872 _exit(1);
875 *error = do_save_command(pwm, password);
876 pinentry_disconnect(pwm);
877 pw.error = *error;
878 write(p[1], &pw, sizeof(pw));
879 close(p[1]);
880 _exit(0);
881 break;
882 case -1:
883 *error = gpg_error_from_syserror();
884 close(p[0]);
885 close(p[1]);
886 return -1;
887 default:
888 break;
891 close(p[1]);
892 return p[0];
895 *error = do_save_getpin(pwm, &password);
897 if (*error)
898 return PWMD_ERROR;
900 else {
901 #endif
902 if (pwm->passfunc) {
903 char *tmp = (*pwm->passfunc)(pwm, pwm->passdata);
905 if (!tmp || !*tmp) {
906 *error = EPWMD_KEY;
907 return PWMD_ERROR;
910 password = xstrdup(tmp);
912 #ifdef USE_PINENTRY
914 #endif
916 if (!password || !*password) {
917 *error = EPWMD_KEY;
918 return PWMD_ERROR;
921 else {
922 if (*error && *error != EPWMD_FILE_NOT_FOUND)
923 return PWMD_ERROR;
926 else
927 password = pwm->password;
929 *error = do_save_command(pwm, password);
931 if (nb)
932 return *error ? -1 : -2;
934 return *error ? PWMD_ERROR : PWMD_OK;
937 int pwmd_save_nb(pwm_t *pwm, gpg_error_t *error)
939 #ifndef USE_PINENTRY
940 *error = GPG_ERR_NOT_IMPLEMENTED;
941 return -1;
942 #else
943 return do_pwmd_save(pwm, error, 1);
944 #endif
947 pwmd_error_t pwmd_save(pwm_t *pwm, gpg_error_t *error)
949 return (pwmd_error_t)do_pwmd_save(pwm, error, 0);
952 pwmd_error_t pwmd_setopt(pwm_t *pwm, gpg_error_t *error, pwmd_option_t opt, ...)
954 va_list ap;
955 #ifdef USE_PINENTRY
956 int n = va_arg(ap, int);
957 #endif
958 char *arg1;
960 if (!pwm)
961 return PWMD_ERROR;
963 va_start(ap, opt);
965 switch (opt) {
966 case PWMD_OPTION_STATUS_FUNC:
967 pwm->status_func = va_arg(ap, pwmd_status_fn);
968 break;
969 case PWMD_OPTION_STATUS_DATA:
970 pwm->status_data = va_arg(ap, void *);
971 break;
972 case PWMD_OPTION_PASSWORD_FUNC:
973 pwm->passfunc = va_arg(ap, pwmd_password_fn);
974 break;
975 case PWMD_OPTION_PASSWORD_DATA:
976 pwm->passdata = va_arg(ap, void *);
977 break;
978 case PWMD_OPTION_PASSWORD:
979 arg1 = va_arg(ap, char *);
981 if (pwm->password)
982 xfree(pwm->password);
984 pwm->password = xstrdup(arg1);
985 break;
986 #ifdef USE_PINENTRY
987 case PWMD_OPTION_PINENTRY:
988 n = va_arg(ap, int);
990 if (n != 0 && n != 1) {
991 va_end(ap);
992 return PWMD_ERROR;
995 pwm->use_pinentry = n;
996 break;
997 case PWMD_OPTION_PINENTRY_TRIES:
998 n = va_arg(ap, int);
1000 if (n <= 0) {
1001 va_end(ap);
1002 return PWMD_ERROR;
1005 pwm->pinentry_tries = n;
1006 break;
1007 case PWMD_OPTION_PINENTRY_PATH:
1008 if (pwm->pinentry_path)
1009 xfree(pwm->pinentry_path);
1011 pwm->pinentry_path = xstrdup(va_arg(ap, char *));
1012 break;
1013 case PWMD_OPTION_PINENTRY_TTY:
1014 if (pwm->pinentry_tty)
1015 xfree(pwm->pinentry_tty);
1017 pwm->pinentry_tty = xstrdup(va_arg(ap, char *));
1018 break;
1019 case PWMD_OPTION_PINENTRY_DISPLAY:
1020 if (pwm->pinentry_display)
1021 xfree(pwm->pinentry_display);
1023 pwm->pinentry_display = xstrdup(va_arg(ap, char *));
1024 break;
1025 case PWMD_OPTION_PINENTRY_TERM:
1026 if (pwm->pinentry_term)
1027 xfree(pwm->pinentry_term);
1029 pwm->pinentry_term = xstrdup(va_arg(ap, char *));
1030 break;
1031 case PWMD_OPTION_PINENTRY_TITLE:
1032 if (pwm->title)
1033 xfree(pwm->title);
1034 pwm->title = percent_escape(va_arg(ap, char *));
1035 break;
1036 case PWMD_OPTION_PINENTRY_PROMPT:
1037 if (pwm->prompt)
1038 xfree(pwm->prompt);
1039 pwm->prompt = percent_escape(va_arg(ap, char *));
1040 break;
1041 case PWMD_OPTION_PINENTRY_DESC:
1042 if (pwm->desc)
1043 xfree(pwm->desc);
1044 pwm->desc = percent_escape(va_arg(ap, char *));
1045 break;
1046 #else
1047 case PWMD_OPTION_PINENTRY:
1048 case PWMD_OPTION_PINENTRY_TRIES:
1049 case PWMD_OPTION_PINENTRY_PATH:
1050 case PWMD_OPTION_PINENTRY_TTY:
1051 case PWMD_OPTION_PINENTRY_DISPLAY:
1052 case PWMD_OPTION_PINENTRY_TERM:
1053 case PWMD_OPTION_PINENTRY_TITLE:
1054 case PWMD_OPTION_PINENTRY_PROMPT:
1055 case PWMD_OPTION_PINENTRY_DESC:
1056 *error = GPG_ERR_NOT_IMPLEMENTED;
1057 return PWMD_ERROR;
1058 #endif
1059 default:
1060 *error = GPG_ERR_NOT_IMPLEMENTED;
1061 va_end(ap);
1062 return PWMD_ERROR;
1065 va_end(ap);
1066 return PWMD_OK;