Made the custom memory allocator symbols hidden. This prevents
[libpwmd.git] / libpwmd.c
blobbc17fb85d1aed0945437cdcd803d69de2b8eb02f
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_func passfunc;
74 void *passdata;
75 pwmd_status_func status_func;
76 void *status_data;
79 typedef struct {
80 size_t len;
81 void *buf;
82 } membuf_t;
84 struct inquire_s {
85 assuan_context_t ctx;
86 const char *buf;
87 size_t len;
90 const char *pwmd_strerror(gpg_error_t pwmd_errno)
92 gpg_err_code_t code = gpg_err_code(pwmd_errno);
94 if (code >= GPG_ERR_USER_1 && code < gpg_err_code(EPWMD_MAX)) {
95 switch (code) {
96 case GPG_ERR_USER_1:
97 default:
98 return "Unknown error";
99 case GPG_ERR_USER_2:
100 return "No cache slots available";
101 case GPG_ERR_USER_3:
102 return "Element not found";
103 case GPG_ERR_USER_4:
104 return "Trailing element";
105 case GPG_ERR_USER_5:
106 return "Invalid character in element";
107 case GPG_ERR_USER_6:
108 return "Empty";
109 case GPG_ERR_USER_7:
110 return "Will not overwrite existing account";
111 case GPG_ERR_USER_8:
112 return "File not found";
113 case GPG_ERR_USER_9:
114 return "No file is open";
115 case GPG_ERR_USER_10:
116 return "General LibXML error";
117 case GPG_ERR_USER_11:
118 return "File not found in cache";
119 case GPG_ERR_USER_12:
120 return "Attribute not found";
121 case GPG_ERR_USER_13:
122 return "Invalid filename or link";
123 case GPG_ERR_USER_14:
124 return "File modified";
128 return gpg_strerror(pwmd_errno);
131 pwmd_error_t pwmd_init()
133 gpg_err_init();
134 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
135 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
137 return PWMD_OK;
140 pwm_t *pwmd_connect(const char *path, gpg_error_t *error)
142 pwm_t *pwm = NULL;
143 char *socketpath = NULL;
144 time_t now;
145 struct passwd *pw;
146 assuan_context_t ctx;
147 int rc;
149 if (!path) {
150 pw = getpwuid(getuid());
151 socketpath = (char *)xmalloc(strlen(pw->pw_dir) + strlen("/.pwmd/socket") + 1);
152 sprintf(socketpath, "%s/.pwmd/socket", pw->pw_dir);
154 else
155 socketpath = xstrdup(path);
157 rc = assuan_socket_connect_ext(&ctx, socketpath, -1, 0);
158 xfree(socketpath);
160 if (rc) {
161 *error = rc;
162 return NULL;
165 if ((pwm = (pwm_t *)xcalloc(1, sizeof(pwm_t))) == NULL) {
166 *error = gpg_error_from_errno(errno);
167 assuan_disconnect(ctx);
168 return NULL;
171 pwm->ctx = ctx;
172 #ifdef USE_PINENTRY
173 pwm->pinentry_tries = 3;
174 #endif
175 time(&now);
176 srandom(now);
177 return pwm;
180 void pwmd_close(pwm_t *pwm)
182 if (!pwm)
183 return;
185 if (pwm->ctx)
186 assuan_disconnect(pwm->ctx);
188 if (pwm->password)
189 xfree(pwm->password);
191 if (pwm->title)
192 xfree(pwm->title);
194 if (pwm->desc)
195 xfree(pwm->desc);
197 if (pwm->prompt)
198 xfree(pwm->prompt);
200 if (pwm->pinentry_tty)
201 xfree(pwm->pinentry_tty);
203 if (pwm->pinentry_display)
204 xfree(pwm->pinentry_display);
206 if (pwm->pinentry_term)
207 xfree(pwm->pinentry_term);
209 if (pwm->filename)
210 xfree(pwm->filename);
212 xfree(pwm);
215 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
217 membuf_t *mem = (membuf_t *)data;
218 void *p;
220 if (!buffer)
221 return 0;
223 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
224 return 1;
226 mem->buf = p;
227 memcpy((char *)mem->buf + mem->len, buffer, len);
228 mem->len += len;
229 return 0;
232 static int inquire_cb(void *data, const char *keyword)
234 struct inquire_s *inquire = (struct inquire_s *)data;
236 return assuan_send_data(inquire->ctx, inquire->buf, inquire->len);
239 void pwmd_free_result(void *data)
241 xfree(data);
244 static gpg_error_t assuan_command(pwm_t *pwm, assuan_context_t ctx,
245 char **result, const char *cmd)
247 membuf_t data;
248 gpg_error_t rc;
250 data.len = 0;
251 data.buf = NULL;
254 * This is needed because assuan only accepts 1000 byte command strings.
255 * If the line is more than this the command will fail. So we use an
256 * INQUIRE on the server which waits for an END that assuan_transact()
257 * fulfills.
259 * Other commands shouldn't need the INQUIRE. Let me know if you have an
260 * element path that's greater than 1000 bytes and I'll fix it.
262 if (strncasecmp(cmd, "STORE", 5) == 0) {
263 const char *p = cmd + 5;
264 struct inquire_s *inq = (struct inquire_s *)xmalloc(sizeof(struct inquire_s));
266 if (*p == ' ')
267 p++;
269 inq->ctx = ctx;
270 inq->buf = p;
271 inq->len = strlen(p);
272 rc = assuan_transact(ctx, "STORE", mem_realloc_cb, &data, inquire_cb,
273 inq, pwm->status_func, pwm->status_data);
274 xfree(inq);
276 else {
277 #ifdef USE_PINENTRY
279 * Ignore any status callback function for pinentry.
281 if (ctx == pwm->pctx)
282 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, NULL, NULL, NULL, NULL);
283 else
284 #endif
285 rc = assuan_transact(ctx, cmd, mem_realloc_cb, &data, NULL, NULL,
286 pwm->status_func, pwm->status_data);
289 if (rc) {
290 if (data.buf) {
291 xfree(data.buf);
292 data.buf = NULL;
295 else {
296 if (data.buf) {
297 mem_realloc_cb(&data, "", 1);
298 *result = (char *)data.buf;
302 return gpg_err_code(rc);
305 #ifdef USE_PINENTRY
307 * which = 0 - normal description from the default or pwm->desc
308 * which = 1 - invalid password
309 * which = 2 - confirm
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;
483 static gpg_error_t 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 pwmd_error_t pwmd_open(pwm_t *pwm, gpg_error_t *error, const char *filename)
501 gpg_error_t n;
502 char *result = NULL;
503 char *password = NULL;
504 static char buf[1000];
505 #ifdef USE_PINENTRY
506 int pin_try = pwm->pinentry_tries - 1;
507 int did_pin = 0;
508 #endif
510 if (!pwm || !filename || !*filename) {
511 *error = EPWMD_ERROR;
512 return PWMD_ERROR;
516 * Avoid calling pinentry if the password is cached on the server.
518 n = pwmd_command(pwm, &result, error, "ISCACHED %s", filename);
520 if (n && (*error == EPWMD_CACHE_NOT_FOUND || *error == EPWMD_FILE_NOT_FOUND)) {
521 if (pwm->passfunc) {
522 password = pwm->passfunc(pwm->passdata);
524 if (!password || !*password) {
525 *error = EPWMD_KEY;
526 return PWMD_ERROR;
529 password = xstrdup(password);
530 goto gotpassword;
533 if (*error == EPWMD_CACHE_NOT_FOUND) {
534 #ifdef USE_PINENTRY
536 * Get the password from pinentry.
538 if (pwm->use_pinentry) {
539 getpin_again:
540 if (did_pin++) {
541 *error = set_pinentry_strings(pwm, 1);
543 if (*error) {
544 pinentry_disconnect(pwm);
545 return PWMD_ERROR;
549 *error = getpin(pwm, &password);
551 if (*error) {
552 if (pin_try-- && *error == EPWMD_KEY)
553 goto getpin_again;
555 if (pwm->pctx)
556 pinentry_disconnect(pwm);
558 return PWMD_ERROR;
561 else {
562 #endif
564 * Not using pinentry and the file was not found
565 * in the cache.
567 if (pwm->password == NULL) {
568 *error = EPWMD_KEY;
569 return PWMD_ERROR;
572 password = pwm->password;
573 #ifdef USE_PINENTRY
575 #endif
577 else if (*error != EPWMD_FILE_NOT_FOUND)
578 return PWMD_ERROR;
581 gotpassword:
582 snprintf(buf, sizeof(buf), "OPEN %s %s", filename, password ? password : "");
583 *error = send_command(pwm, NULL, buf);
584 memset(&buf, 0, sizeof(buf));
585 xfree(password);
587 #ifdef USE_PINENTRY
588 if (pwm->pctx && *error == EPWMD_BADKEY) {
589 if (pin_try--)
590 goto getpin_again;
592 pinentry_disconnect(pwm);
593 return PWMD_ERROR;
596 if (pwm->pctx)
597 pinentry_disconnect(pwm);
598 #endif
600 if (!pwm->use_pinentry && pwm->password)
601 pwm->password = NULL;
603 if (!*error) {
604 if (pwm->filename)
605 xfree(pwm->filename);
607 pwm->filename = xstrdup(filename);
610 return *error ? PWMD_ERROR : PWMD_OK;
613 pwmd_error_t pwmd_save(pwm_t *pwm, gpg_error_t *error)
615 char *result = NULL;
616 gpg_error_t n;
617 char *password = NULL;
618 char *p;
619 static char buf[1000];
621 if (!pwm)
622 return PWMD_ERROR;
624 #ifdef USE_PINENTRY
625 if (pwm->use_pinentry || pwm->passfunc) {
626 #else
627 if (pwm->passfunc) {
628 #endif
629 n = pwmd_command(pwm, &result, error, "ISCACHED %s", pwm->filename);
631 if (n == PWMD_ERROR && (*error == EPWMD_CACHE_NOT_FOUND || *error == EPWMD_FILE_NOT_FOUND)) {
632 #ifdef USE_PINENTRY
633 int confirm = 0;
635 if (pwm->use_pinentry) {
636 again:
637 if (confirm) {
638 *error = set_pinentry_strings(pwm, 2);
640 if (*error) {
641 if (pwm->pctx)
642 pinentry_disconnect(pwm);
644 if (password)
645 xfree(password);
647 return PWMD_ERROR;
651 *error = getpin(pwm, &result);
653 if (*error) {
654 if (pwm->pctx)
655 pinentry_disconnect(pwm);
657 if (password)
658 xfree(password);
660 return PWMD_ERROR;
663 if (!confirm++) {
664 password = result;
665 goto again;
668 if (strcmp(password, result)) {
669 xfree(password);
670 xfree(result);
671 pinentry_disconnect(pwm);
672 *error = EPWMD_BADKEY;
673 return PWMD_ERROR;
676 xfree(result);
677 pinentry_disconnect(pwm);
679 else {
680 #endif
681 if (pwm->passfunc) {
682 password = (*pwm->passfunc)(pwm->passdata);
684 if (!password) {
685 *error = EPWMD_KEY;
686 return PWMD_ERROR;
689 #ifdef USE_PINENTRY
691 #endif
693 if (!password || !*password) {
694 *error = EPWMD_KEY;
695 return PWMD_ERROR;
698 p = xstrdup(password);
700 #ifdef USE_PINENTRY
701 if (!pwm->use_pinentry) {
702 memset(password, 0, strlen(password));
703 free(password);
705 else
706 xfree(password);
708 #else
709 memset(password, 0, strlen(password));
710 free(password);
711 #endif
712 password = p;
714 else {
715 if (n != PWMD_OK)
716 return PWMD_ERROR;
719 else
720 password = pwm->password;
722 snprintf(buf, sizeof(buf), "SAVE %s", password ? password : "");
723 *error = send_command(pwm, NULL, buf);
724 memset(&buf, 0, sizeof(buf));
725 xfree(password);
726 pwm->password = NULL;
727 return *error ? PWMD_ERROR : PWMD_OK;
730 pwmd_error_t pwmd_setopt(pwm_t *pwm, gpg_error_t *error, pwmd_option_t opt, ...)
732 va_list ap;
733 #ifdef USE_PINENTRY
734 int n = va_arg(ap, int);
735 #endif
736 char *arg1;
738 if (!pwm)
739 return PWMD_ERROR;
741 va_start(ap, opt);
743 switch (opt) {
744 case PWMD_OPTION_STATUS_FUNC:
745 pwm->status_func = va_arg(ap, pwmd_status_func);
746 break;
747 case PWMD_OPTION_STATUS_DATA:
748 pwm->status_data = va_arg(ap, void *);
749 break;
750 case PWMD_OPTION_PASSWORD_FUNC:
751 pwm->passfunc = va_arg(ap, pwmd_password_func);
752 break;
753 case PWMD_OPTION_PASSWORD_DATA:
754 pwm->passdata = va_arg(ap, void *);
755 break;
756 case PWMD_OPTION_PASSWORD:
757 arg1 = va_arg(ap, char *);
759 if (pwm->password)
760 xfree(pwm->password);
762 pwm->password = xstrdup(arg1);
763 break;
764 #ifdef USE_PINENTRY
765 case PWMD_OPTION_PINENTRY:
766 n = va_arg(ap, int);
768 if (n != 0 && n != 1) {
769 va_end(ap);
770 return PWMD_ERROR;
773 pwm->use_pinentry = n;
774 break;
775 case PWMD_OPTION_PINENTRY_TRIES:
776 n = va_arg(ap, int);
778 if (n <= 0) {
779 va_end(ap);
780 return PWMD_ERROR;
783 pwm->pinentry_tries = n;
784 break;
785 case PWMD_OPTION_PINENTRY_PATH:
786 if (pwm->pinentry_path)
787 xfree(pwm->pinentry_path);
789 pwm->pinentry_path = xstrdup(va_arg(ap, char *));
790 break;
791 case PWMD_OPTION_PINENTRY_TTY:
792 if (pwm->pinentry_tty)
793 xfree(pwm->pinentry_tty);
795 pwm->pinentry_tty = xstrdup(va_arg(ap, char *));
796 break;
797 case PWMD_OPTION_PINENTRY_DISPLAY:
798 if (pwm->pinentry_display)
799 xfree(pwm->pinentry_display);
801 pwm->pinentry_display = xstrdup(va_arg(ap, char *));
802 break;
803 case PWMD_OPTION_PINENTRY_TERM:
804 if (pwm->pinentry_term)
805 xfree(pwm->pinentry_term);
807 pwm->pinentry_term = xstrdup(va_arg(ap, char *));
808 break;
809 case PWMD_OPTION_PINENTRY_TITLE:
810 if (pwm->title)
811 xfree(pwm->title);
812 pwm->title = percent_escape(va_arg(ap, char *));
813 break;
814 case PWMD_OPTION_PINENTRY_PROMPT:
815 if (pwm->prompt)
816 xfree(pwm->prompt);
817 pwm->prompt = percent_escape(va_arg(ap, char *));
818 break;
819 case PWMD_OPTION_PINENTRY_DESC:
820 if (pwm->desc)
821 xfree(pwm->desc);
822 pwm->desc = percent_escape(va_arg(ap, char *));
823 break;
824 #else
825 case PWMD_OPTION_PINENTRY:
826 case PWMD_OPTION_PINENTRY_TRIES:
827 case PWMD_OPTION_PINENTRY_PATH:
828 case PWMD_OPTION_PINENTRY_TTY:
829 case PWMD_OPTION_PINENTRY_DISPLAY:
830 case PWMD_OPTION_PINENTRY_TERM:
831 case PWMD_OPTION_PINENTRY_TITLE:
832 case PWMD_OPTION_PINENTRY_PROMPT:
833 case PWMD_OPTION_PINENTRY_DESC:
834 *error = GPG_ERR_NOT_IMPLEMENTED;
835 return PWMD_ERROR;
836 #endif
837 default:
838 *error = GPG_ERR_NOT_IMPLEMENTED;
839 va_end(ap);
840 return PWMD_ERROR;
843 va_end(ap);
844 return PWMD_OK;
847 int pwmd_get_password(pwm_t *pwm, gpg_error_t *error, const char *filename)
849 gpg_error_t n;
850 char *result;
851 #ifdef USE_PINENTRY
852 int p[2];
853 pid_t pid;
854 char *password = NULL;
855 pwmd_password_t pw;
857 memset(&pw, 0, sizeof(pw));
858 #endif
860 if (!pwm) {
861 *error = EPWMD_ERROR;
862 return PWMD_ERROR;
865 if (filename) {
866 n = pwmd_command(pwm, &result, error, "ISCACHED %s", filename);
868 if (n != PWMD_OK && *error != EPWMD_CACHE_NOT_FOUND && *error != EPWMD_FILE_NOT_FOUND)
869 return -1;
871 * Don't need a password for non-existant files.
873 else if ((n != PWMD_OK && *error == EPWMD_FILE_NOT_FOUND) || n == PWMD_OK) {
874 *error = 0;
875 return -2;
879 #ifdef USE_PINENTRY
880 if (pipe(p) == -1) {
881 *error = gpg_error_from_syserror();
882 return -1;
885 pid = fork();
887 switch (pid) {
888 case 0:
889 close(p[0]);
890 n = pinentry_command(pwm, &password, "GETPIN");
892 if (n) {
893 close(p[1]);
895 if (pwm->pctx)
896 pinentry_disconnect(pwm);
898 pw.error = n;
899 write(p[1], &pw, sizeof(pw));
900 _exit(1);
903 if (!password || !*password)
904 pw.error = EPWMD_KEY;
905 else
906 strncpy(pw.password, password, sizeof(pw.password));
908 write(p[1], &pw, sizeof(pw));
909 memset(&pw.password, 0, sizeof(pw.password));
910 xfree(password);
911 close(p[1]);
912 _exit(0);
913 case -1:
914 *error = gpg_error_from_syserror();
915 close(p[0]);
916 close(p[1]);
917 return -1;
918 default:
919 break;
922 close(p[1]);
923 return p[0];
924 #else
925 *error = GPG_ERR_NOT_IMPLEMENTED;
926 return -1;
927 #endif