Make the filename argument to pwmc optional. The command may be a
[libpwmd.git] / libpwmd.c
blobfbf14081b41ccc8d6c118a5853e3e22fb5ad4866
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"
51 #ifdef USE_PINENTRY
52 #define PINENTRY_PATH "/usr/bin/pinentry"
53 static gpg_error_t pinentry_command(pwm_t *pwm, char **result, const char *cmd);
54 #endif
56 struct pwm_s {
57 assuan_context_t ctx;
58 #ifdef USE_PINENTRY
59 assuan_context_t pctx; /* pinentry */
60 #endif
61 int use_pinentry;
62 int pinentry_tries;
63 char *pinentry_path;
64 char *pinentry_tty;
65 char *pinentry_term;
66 char *pinentry_display;
67 char *title;
68 char *prompt;
69 char *desc;
70 char *password;
71 char *filename;
72 pwmd_password_fn passfunc;
73 void *passdata;
74 pwmd_status_fn status_func;
75 void *status_data;
78 typedef struct {
79 size_t len;
80 void *buf;
81 } membuf_t;
83 struct inquire_s {
84 assuan_context_t ctx;
85 const char *buf;
86 size_t len;
89 const char *pwmd_strerror(gpg_error_t pwmd_errno)
91 gpg_err_code_t code = gpg_err_code(pwmd_errno);
93 if (code >= GPG_ERR_USER_1 && code < gpg_err_code(EPWMD_MAX)) {
94 switch (code) {
95 case GPG_ERR_USER_1:
96 default:
97 return "Unknown error";
98 case GPG_ERR_USER_2:
99 return "No cache slots available";
100 case GPG_ERR_USER_3:
101 return "Element not found";
102 case GPG_ERR_USER_4:
103 return "Trailing element";
104 case GPG_ERR_USER_5:
105 return "Invalid character in element";
106 case GPG_ERR_USER_6:
107 return "Empty";
108 case GPG_ERR_USER_7:
109 return "Will not overwrite existing account";
110 case GPG_ERR_USER_8:
111 return "File not found";
112 case GPG_ERR_USER_9:
113 return "No file is open";
114 case GPG_ERR_USER_10:
115 return "General LibXML error";
116 case GPG_ERR_USER_11:
117 return "File not found in cache";
118 case GPG_ERR_USER_12:
119 return "Attribute not found";
120 case GPG_ERR_USER_13:
121 return "Invalid filename or link";
122 case GPG_ERR_USER_14:
123 return "File modified";
127 return gpg_strerror(pwmd_errno);
130 pwmd_error_t pwmd_init()
132 gpg_err_init();
133 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
134 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
136 return PWMD_OK;
139 pwm_t *pwmd_connect(const char *path, gpg_error_t *error)
141 pwm_t *pwm = NULL;
142 char *socketpath = NULL;
143 time_t now;
144 struct passwd *pw;
145 assuan_context_t ctx;
146 int rc;
148 if (!path) {
149 pw = getpwuid(getuid());
150 socketpath = (char *)xmalloc(strlen(pw->pw_dir) + strlen("/.pwmd/socket") + 1);
151 sprintf(socketpath, "%s/.pwmd/socket", pw->pw_dir);
153 else
154 socketpath = xstrdup(path);
156 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
157 xfree(socketpath);
159 if (rc) {
160 *error = rc;
161 return NULL;
164 if ((pwm = (pwm_t *)xcalloc(1, sizeof(pwm_t))) == NULL) {
165 *error = gpg_error_from_errno(errno);
166 assuan_disconnect(ctx);
167 return NULL;
170 pwm->ctx = ctx;
171 #ifdef USE_PINENTRY
172 pwm->pinentry_tries = 3;
173 #endif
174 time(&now);
175 srandom(now);
176 return pwm;
179 void pwmd_close(pwm_t *pwm)
181 if (!pwm)
182 return;
184 if (pwm->ctx)
185 assuan_disconnect(pwm->ctx);
187 if (pwm->password)
188 xfree(pwm->password);
190 if (pwm->title)
191 xfree(pwm->title);
193 if (pwm->desc)
194 xfree(pwm->desc);
196 if (pwm->prompt)
197 xfree(pwm->prompt);
199 if (pwm->pinentry_tty)
200 xfree(pwm->pinentry_tty);
202 if (pwm->pinentry_display)
203 xfree(pwm->pinentry_display);
205 if (pwm->pinentry_term)
206 xfree(pwm->pinentry_term);
208 if (pwm->filename)
209 xfree(pwm->filename);
211 xfree(pwm);
214 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
216 membuf_t *mem = (membuf_t *)data;
217 void *p;
219 if (!buffer)
220 return 0;
222 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
223 return 1;
225 mem->buf = p;
226 memcpy((char *)mem->buf + mem->len, buffer, len);
227 mem->len += len;
228 return 0;
231 static int inquire_cb(void *data, const char *keyword)
233 struct inquire_s *inquire = (struct inquire_s *)data;
235 return assuan_send_data(inquire->ctx, inquire->buf, inquire->len);
238 void pwmd_free_result(void *data)
240 xfree(data);
243 static gpg_error_t assuan_command(pwm_t *pwm, assuan_context_t ctx,
244 char **result, const char *cmd)
246 membuf_t data;
247 gpg_error_t rc;
249 data.len = 0;
250 data.buf = NULL;
253 * This is needed because assuan only accepts 1000 byte command strings.
254 * If the line is more than this the command will fail. So we use an
255 * INQUIRE on the server which waits for an END that assuan_transact()
256 * fulfills.
258 * Other commands shouldn't need the INQUIRE. Let me know if you have an
259 * element path that's greater than 1000 bytes and I'll fix it.
261 if (strncasecmp(cmd, "STORE", 5) == 0) {
262 const char *p = cmd + 5;
263 struct inquire_s *inq = (struct inquire_s *)xmalloc(sizeof(struct inquire_s));
265 if (*p == ' ')
266 p++;
268 inq->ctx = ctx;
269 inq->buf = p;
270 inq->len = strlen(p);
271 rc = assuan_transact(ctx, "STORE", mem_realloc_cb, &data, inquire_cb,
272 inq, pwm->status_func, pwm->status_data);
273 xfree(inq);
275 else {
276 #ifdef USE_PINENTRY
278 * Ignore any status callback function for pinentry.
280 if (ctx == pwm->pctx)
281 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, NULL, NULL, NULL, NULL);
282 else
283 #endif
284 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, NULL, NULL,
285 pwm->status_func, pwm->status_data);
288 if (rc) {
289 if (data.buf) {
290 xfree(data.buf);
291 data.buf = NULL;
294 else {
295 if (data.buf) {
296 mem_realloc_cb(&data, "", 1);
297 *result = (char *)data.buf;
301 return gpg_err_code(rc);
304 #ifdef USE_PINENTRY
305 static gpg_error_t set_pinentry_strings(pwm_t *pwm, int which)
307 char *buf;
308 gpg_error_t error;
310 if (!pwm->title)
311 pwm->title = xstrdup("LibPWMD");
313 if (!pwm->prompt)
314 pwm->prompt = xstrdup("Password:");
316 if (!pwm->desc && !which)
317 pwm->desc = xstrdup("Enter a password.");
319 if (which == 1)
320 buf = xstrdup("SETERROR Invalid password, please try again.");
321 else if (which == 2)
322 buf = xstrdup("SETERROR Please type the password again for confirmation.");
323 else {
324 buf = (char *)xmalloc(strlen("SETERROR ") + strlen(pwm->desc) + 1);
325 sprintf(buf, "SETERROR %s", pwm->desc);
328 error = pinentry_command(pwm, NULL, buf);
329 xfree(buf);
331 if (error)
332 return error;
334 buf = (char *)xmalloc(strlen("SETPROMPT ") + strlen(pwm->prompt) + 1);
335 sprintf(buf, "SETPROMPT %s", pwm->prompt);
336 error = pinentry_command(pwm, NULL, buf);
337 xfree(buf);
339 if (error)
340 return error;
342 buf = (char *)xmalloc(strlen("SETDESC ") + strlen(pwm->title) + 1);
343 sprintf(buf, "SETDESC %s", pwm->title);
344 error = pinentry_command(pwm, NULL, buf);
345 xfree(buf);
346 return error;
349 static gpg_error_t launch_pinentry(pwm_t *pwm)
351 int rc;
352 assuan_context_t ctx;
353 int child_list[] = {-1};
354 char *display = getenv("DISPLAY");
355 const char *argv[6];
356 int have_display = 0;
357 char *tty = NULL;
359 if (pwm->pinentry_display || display)
360 have_display = 1;
361 else {
362 tty = pwm->pinentry_tty ? pwm->pinentry_tty : ttyname(STDOUT_FILENO);
364 if (!tty)
365 return gpg_error_from_errno(errno);
368 if (!display && !tty)
369 return GPG_ERR_ENOTTY;
371 argv[0] = "pinentry";
372 argv[1] = have_display ? "--display" : "--ttyname";
373 argv[2] = have_display ? pwm->pinentry_display ? pwm->pinentry_display : display : tty;
374 argv[3] = NULL;
376 if (!have_display) {
377 argv[3] = "--ttytype";
378 argv[4] = pwm->pinentry_term ? pwm->pinentry_term : getenv("TERM");
379 argv[5] = NULL;
382 rc = assuan_pipe_connect(&ctx, pwm->pinentry_path ? pwm->pinentry_path : PINENTRY_PATH, argv, child_list);
384 if (rc)
385 return rc;
387 pwm->pctx = ctx;
388 return set_pinentry_strings(pwm, 0);
391 static gpg_error_t pinentry_command(pwm_t *pwm, char **result, const char *cmd)
393 gpg_error_t n;
395 if (!pwm->pctx) {
396 n = launch_pinentry(pwm);
398 if (n)
399 return n;
402 return assuan_command(pwm, pwm->pctx, result, cmd);
405 static void pinentry_disconnect(pwm_t *pwm)
407 assuan_disconnect(pwm->pctx);
408 pwm->pctx = NULL;
411 static char *percent_escape(const char *atext)
413 const unsigned char *s;
414 int len = strlen(atext) * 3 + 1;
415 char *buf = (char *)xmalloc(len), *p = buf;
417 if (!buf)
418 return NULL;
420 for (s=(const unsigned char *)atext; *s; s++) {
421 if (*s < ' ') {
422 sprintf (p, "%%%02X", *s);
423 p += 3;
425 else
426 *p++ = *s;
429 *p = 0;
430 return buf;
432 #endif
434 static gpg_error_t send_command(pwm_t *pwm, char **result, const char *cmd)
436 if (!cmd)
437 return EPWMD_ERROR;
439 return assuan_command(pwm, pwm->ctx, result, cmd);
443 * Avoid sending the BYE command here. libassuan will close the file
444 * descriptor and release the assuan context. Use pwmd_close() instead.
446 pwmd_error_t pwmd_command(pwm_t *pwm, char **result, gpg_error_t *error, const char *cmd, ...)
448 va_list ap;
449 char *buf;
450 size_t len;
452 if (!pwm)
453 return PWMD_ERROR;
455 if (!cmd) {
456 *error = EPWMD_COMMAND_SYNTAX;
457 return PWMD_ERROR;
460 *result = NULL;
461 *error = EPWMD_ERROR;
463 va_start(ap, cmd);
465 * C99
467 len = vsnprintf(NULL, 0, cmd, ap);
468 buf = (char *)xmalloc(len + 1);
469 len = vsnprintf(buf, len + 1, cmd, ap);
470 va_end(ap);
471 *error = send_command(pwm, result, buf);
472 xfree(buf);
473 return *error ? PWMD_ERROR : PWMD_OK;
476 #ifdef USE_PINENTRY
477 static gpg_error_t do_getpin(pwm_t *pwm, char **result)
479 gpg_error_t error;
481 *result = NULL;
482 error = pinentry_command(pwm, result, "GETPIN");
484 if (error == GPG_ERR_ASS_CANCELED)
485 return error;
487 if (!*result)
488 return EPWMD_KEY;
490 return 0;
493 static pwmd_error_t getpin(pwm_t *pwm, char **result, gpg_error_t *error,
494 int *try, int which)
496 int pin_try = *try;
498 getpin_again:
499 *try = pin_try;
501 if (pin_try == -1) {
502 *error = set_pinentry_strings(pwm, which);
504 if (*error) {
505 pinentry_disconnect(pwm);
506 return PWMD_ERROR;
509 else {
510 if (pwm->pinentry_tries-1 != pin_try) {
511 *error = set_pinentry_strings(pwm, 1);
513 if (*error) {
514 pinentry_disconnect(pwm);
515 return PWMD_ERROR;
520 *error = do_getpin(pwm, result);
522 if (*error) {
523 if (pin_try != -1 && pin_try-- && *error == EPWMD_KEY)
524 goto getpin_again;
526 if (pwm->pctx)
527 pinentry_disconnect(pwm);
529 *try = pin_try;
530 return PWMD_ERROR;
533 return PWMD_OK;
536 pwmd_error_t pwmd_open_nb_finalize(pwm_t *pwm, gpg_error_t *error,
537 pwmd_nb_status_t *pw)
539 char *result;
541 if (!pwm || !pw || !pw->filename[0])
542 return PWMD_ERROR;
544 close(pw->fd);
546 if (pw->error) {
547 *error = pw->error;
548 goto fail;
551 if (pwmd_command(pwm, &result, error, "ISCACHED %s", pw->filename) != PWMD_OK)
552 goto fail;
554 if (pwm->filename)
555 xfree(pwm->filename);
557 pwm->filename = xstrdup(pw->filename);
558 memset(pw, 0, sizeof(pwmd_nb_status_t));
559 return PWMD_OK;
561 fail:
562 memset(pw, 0, sizeof(pwmd_nb_status_t));
563 return PWMD_ERROR;
565 #endif
567 static gpg_error_t do_open_command(pwm_t *pwm, const char *filename, char *password)
569 char buf[1000];
570 gpg_error_t error;
572 snprintf(buf, sizeof(buf), "OPEN %s %s", filename, password ? password : "");
573 error = send_command(pwm, NULL, buf);
574 memset(&buf, 0, sizeof(buf));
575 xfree(password);
576 return error;
579 static int do_pwmd_open(pwm_t *pwm, gpg_error_t *error, const char *filename,
580 int nb)
582 char *result = NULL;
583 char *password = NULL;
584 #ifdef USE_PINENTRY
585 int pin_try = pwm->pinentry_tries - 1;
586 #endif
588 if (!pwm || !filename || !*filename) {
589 *error = EPWMD_ERROR;
590 return PWMD_ERROR;
594 * Avoid calling pinentry if the password is cached on the server.
596 pwmd_command(pwm, &result, error, "ISCACHED %s", filename);
598 if (*error == EPWMD_CACHE_NOT_FOUND) {
599 if (pwm->passfunc) {
600 password = pwm->passfunc(pwm, pwm->passdata);
602 if (!password || !*password) {
603 *error = EPWMD_KEY;
604 return PWMD_ERROR;
607 password = xstrdup(password);
608 goto gotpassword;
611 if (*error == EPWMD_CACHE_NOT_FOUND) {
612 #ifdef USE_PINENTRY
614 * Get the password from pinentry.
616 if (pwm->use_pinentry) {
618 * Nonblocking is wanted. fork() then return a file descriptor
619 * that the client can use to read() from.
621 if (nb) {
622 int p[2];
623 pid_t pid;
624 pwmd_nb_status_t pw;
626 if (pipe(p) == -1) {
627 *error = gpg_error_from_syserror();
628 return -1;
631 pid = fork();
633 switch (pid) {
634 case 0:
635 close(p[0]);
636 strncpy(pw.filename, filename, sizeof(pw.filename));
637 pw.fd = p[0];
638 getpin_nb_again:
639 getpin(pwm, &password, error, &pin_try, 0);
641 if (*error) {
642 getpin_nb_fail:
643 if (pwm->pctx)
644 pinentry_disconnect(pwm);
646 pw.error = *error;
647 write(p[1], &pw, sizeof(pw));
648 close(p[1]);
649 _exit(1);
652 *error = do_open_command(pwm, filename, password);
654 if (pwm->pctx && *error == EPWMD_BADKEY) {
655 if (pin_try-- > 0)
656 goto getpin_nb_again;
658 goto getpin_nb_fail;
661 pinentry_disconnect(pwm);
662 pw.error = 0;
663 write(p[1], &pw, sizeof(pw));
664 close(p[1]);
665 _exit(0);
666 break;
667 case -1:
668 *error = gpg_error_from_syserror();
669 close(p[0]);
670 close(p[1]);
671 return -1;
672 default:
673 break;
676 close(p[1]);
677 return p[0];
680 getpin_again:
681 getpin(pwm, &password, error, &pin_try, 1);
683 if (*error) {
684 if (pwm->pctx)
685 pinentry_disconnect(pwm);
687 return PWMD_ERROR;
690 else {
691 #endif
693 * Not using pinentry and the file was not found
694 * in the cache.
696 if (pwm->password == NULL) {
697 *error = EPWMD_KEY;
698 return PWMD_ERROR;
701 password = pwm->password;
702 #ifdef USE_PINENTRY
704 #endif
707 else if (*error && *error != EPWMD_FILE_NOT_FOUND)
708 return PWMD_ERROR;
710 gotpassword:
711 *error = do_open_command(pwm, filename, password);
713 #ifdef USE_PINENTRY
714 if (pwm->pctx && *error == EPWMD_BADKEY) {
715 if (pin_try-- > 0)
716 goto getpin_again;
718 pinentry_disconnect(pwm);
719 return PWMD_ERROR;
721 #endif
723 if (!pwm->use_pinentry && pwm->password)
724 pwm->password = NULL;
726 if (!*error) {
727 if (pwm->filename)
728 xfree(pwm->filename);
730 pwm->filename = xstrdup(filename);
734 * The file is cached or the file is a new file.
736 if (nb)
737 return *error ? -1 : -2;
739 return *error ? PWMD_ERROR : PWMD_OK;
742 pwmd_error_t pwmd_open(pwm_t *pwm, gpg_error_t *error, const char *filename)
744 return (pwmd_error_t)do_pwmd_open(pwm, error, filename, 0);
747 int pwmd_open_nb(pwm_t *pwm, gpg_error_t *error, const char *filename)
749 #ifndef USE_PINENTRY
750 *error = GPG_ERR_NOT_IMPLEMENTED;
751 return -1;
752 #else
753 return do_pwmd_open(pwm, error, filename, 1);
754 #endif
757 #ifdef USE_PINENTRY
758 static gpg_error_t do_save_getpin(pwm_t *pwm, char **password)
760 int confirm = 0;
761 gpg_error_t error;
762 char *result = NULL;
763 int pin_try = -1;
765 again:
766 getpin(pwm, &result, &error, &pin_try, confirm ? 2 : 0);
768 if (error) {
769 if (pwm->pctx)
770 pinentry_disconnect(pwm);
772 if (*password)
773 xfree(*password);
775 return error;
778 if (!confirm++) {
779 *password = result;
780 goto again;
783 if (strcmp(*password, result)) {
784 xfree(*password);
785 xfree(result);
786 pinentry_disconnect(pwm);
787 error = EPWMD_BADKEY;
788 return error;
791 xfree(result);
792 pinentry_disconnect(pwm);
793 return 0;
795 #endif
797 static gpg_error_t do_save_command(pwm_t *pwm, char *password)
799 char buf[ASSUAN_LINELENGTH];
800 gpg_error_t error;
802 snprintf(buf, sizeof(buf), "SAVE %s", password ? password : "");
803 error = send_command(pwm, NULL, buf);
804 memset(&buf, 0, sizeof(buf));
805 xfree(password);
806 pwm->password = NULL;
807 return error;
810 pwmd_error_t pwmd_save_nb_finalize(pwm_t *pwm, gpg_error_t *error,
811 pwmd_nb_status_t *pw)
813 if (!pwm || !pw || !pw->filename[0])
814 return PWMD_ERROR;
816 close(pw->fd);
818 if (pw->error) {
819 *error = pw->error;
820 memset(pw, 0, sizeof(pwmd_nb_status_t));
821 return PWMD_ERROR;
824 memset(pw, 0, sizeof(pwmd_nb_status_t));
825 return PWMD_OK;
828 static int do_pwmd_save(pwm_t *pwm, gpg_error_t *error, int nb)
830 char *result = NULL;
831 char *password = NULL;
833 if (!pwm)
834 return PWMD_ERROR;
836 if (pwm->use_pinentry || pwm->passfunc) {
837 pwmd_command(pwm, &result, error, "ISCACHED %s", pwm->filename);
839 if (*error == EPWMD_CACHE_NOT_FOUND) {
840 #ifdef USE_PINENTRY
841 if (pwm->use_pinentry) {
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, pwm->filename, sizeof(pw.filename));
858 pw.fd = p[0];
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;