1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 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
26 #define _ASSUAN_ONLY_GPG_ERRORS 1
36 #include "pwmd_error.h"
37 #include "assuan-errors.h"
44 static struct client_s
*global_client
;
47 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
);
49 /* Borrowed from libassuan 1.0.4 svn 277 */
50 /* Helper to map old style Assuan error codes to gpg-error codes.
51 This is used internally to keep an compatible ABI. */
53 _assuan_error (int oldcode
)
60 case ASSUAN_General_Error
: n
= 257; break;
61 case ASSUAN_Accept_Failed
: n
= 258; break;
62 case ASSUAN_Connect_Failed
: n
= 259; break;
63 case ASSUAN_Invalid_Response
: n
= 260; break;
64 case ASSUAN_Invalid_Value
: n
= 261; break;
65 case ASSUAN_Line_Not_Terminated
: n
= 262; break;
66 case ASSUAN_Line_Too_Long
: n
= 263; break;
67 case ASSUAN_Nested_Commands
: n
= 264; break;
68 case ASSUAN_No_Data_Callback
: n
= 265; break;
69 case ASSUAN_No_Inquire_Callback
: n
= 266; break;
70 case ASSUAN_Not_A_Server
: n
= 267; break;
71 case ASSUAN_Not_Implemented
: n
= 69; break;
72 case ASSUAN_Parameter_Conflict
: n
= 280; break;
73 case ASSUAN_Problem_Starting_Server
: n
= 269; break;
74 case ASSUAN_Server_Fault
: n
= 80; break;
75 case ASSUAN_Syntax_Error
: n
= 276; break;
76 case ASSUAN_Too_Much_Data
: n
= 273; break;
77 case ASSUAN_Unexpected_Command
: n
= 274; break;
78 case ASSUAN_Unknown_Command
: n
= 275; break;
79 case ASSUAN_Canceled
: n
= 277; break;
80 case ASSUAN_No_Secret_Key
: n
= 17; break;
81 case ASSUAN_Not_Confirmed
: n
= 114; break;
83 case ASSUAN_Read_Error
:
86 case 0: n
= 16381; /*GPG_ERR_MISSING_ERRNO*/ break;
90 default: n
= 270; /*GPG_ERR_ASS_READ_ERROR*/ break;
94 case ASSUAN_Write_Error
:
97 case 0: n
= 16381; /*GPG_ERR_MISSING_ERRNO*/ break;
101 default: n
= 271; /*GPG_ERR_ASS_WRITE_ERROR*/ break;
105 case ASSUAN_Out_Of_Core
:
108 case 0: /* Should not happen but a user might have provided
109 an incomplete implemented malloc function. Give
110 him a chance to correct this fault but make sure
111 an error is indeed returned. */
112 n
= 16381; /*GPG_ERR_MISSING_ERRNO*/
115 n
= (86 | (1 << 15));
118 n
= 16382; /*GPG_ERR_UNKNOWN_ERRNO*/
123 case -1: n
= 16383 /*GPG_ERR_EOF*/; break;
130 return ((err_source
<< 24) | (n
& 0x00ffffff));
133 static int mem_realloc_cb(void *data
, const void *buffer
, size_t len
)
135 membuf_t
*mem
= (membuf_t
*)data
;
141 if ((p
= xrealloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
145 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
150 static gpg_error_t
assuan_command(struct pinentry_s
*pin
, char **result
,
159 rc
= assuan_transact(pin
->ctx
, cmd
, mem_realloc_cb
, &data
, NULL
, NULL
,
170 mem_realloc_cb(&data
, "", 1);
171 *result
= (gchar
*)data
.buf
;
178 static gpg_error_t
launch_pinentry(struct pinentry_s
*pin
)
181 assuan_context_t ctx
;
182 int child_list
[] = {-1};
183 char *display
= getenv("DISPLAY");
185 int have_display
= 0;
188 //update_pinentry_settings(pin);
190 if (pin
->display
|| display
)
193 tty
= pin
->ttyname
? pin
->ttyname
: ttyname(STDOUT_FILENO
);
196 return _assuan_error(ASSUAN_Invalid_Value
);
200 if (!have_display
&& !tty
)
201 return _assuan_error(ASSUAN_Invalid_Value
);
203 argv
[0] = "pinentry";
204 argv
[1] = have_display
? "--display" : "--ttyname";
205 argv
[2] = have_display
? pin
->display
? pin
->display
: display
: tty
;
209 gchar
*p
= getenv("TERM");
212 argv
[3] = "--ttytype";
213 argv
[4] = pin
->ttytype
? pin
->ttytype
: p
;
217 return _assuan_error(ASSUAN_Invalid_Value
);
220 rc
= assuan_pipe_connect(&ctx
, pin
->path
? pin
->path
: PINENTRY_PATH
,
224 return _assuan_error(rc
);
226 pin
->pid
= assuan_get_pid(ctx
);
228 return set_pinentry_strings(pin
, 0);
231 static gpg_error_t
pinentry_command(struct pinentry_s
*pin
, gchar
**result
,
234 gpg_error_t error
= 0;
237 error
= launch_pinentry(pin
);
239 return error
? error
: assuan_command(pin
, result
, cmd
);
242 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
)
249 title
= g_strdup(N_("Password mismatch, please try again."));
250 else if (!pin
->title
)
251 title
= pin
->title
= g_strdup(N_("Password Manager Daemon"));
256 pin
->prompt
= g_strdup(N_("Password:"));
258 if (!pin
->desc
&& !which
)
259 pin
->desc
= g_strdup_printf(pin
->which
== PINENTRY_OPEN
?
260 N_("A password is required to open the file \"%s\". Please%%0Aenter the password below.") :
261 N_("A password is required to save to the file \"%s\". Please%%0Aenter the password below."),
265 buf
= g_strdup_printf("SETERROR %s", N_("Please type the password again for confirmation."));
267 buf
= g_strdup_printf("SETERROR %s", pin
->desc
);
269 error
= pinentry_command(pin
, NULL
, buf
);
275 buf
= g_strdup_printf("SETPROMPT %s", pin
->prompt
);
276 error
= pinentry_command(pin
, NULL
, buf
);
282 buf
= g_strdup_printf("SETDESC %s", title
);
283 error
= pinentry_command(pin
, NULL
, buf
);
293 static void pinentry_disconnect(struct pinentry_s
*pin
)
299 assuan_disconnect(pin
->ctx
);
305 static gpg_error_t
do_getpin(struct pinentry_s
*pin
, char **result
)
310 error
= pinentry_command(pin
, result
, "GETPIN");
313 error
= _assuan_error(error
);
315 *result
= xstrdup("");
320 static gpg_error_t
getpin(struct pinentry_s
*pin
, gchar
**result
)
323 gpg_error_t error
= set_pinentry_strings(pin
, which
);
324 gchar
*result1
= NULL
;
327 pinentry_disconnect(pin
);
332 error
= do_getpin(pin
, result
);
337 if (pin
->which
== PINENTRY_SAVE
) {
339 error
= set_pinentry_strings(pin
, 2);
344 result1
= g_strdup(*result
);
348 if (strcmp(result1
, *result
)) {
351 result1
= *result
= NULL
;
352 error
= set_pinentry_strings(pin
, 1);
363 pinentry_disconnect(pin
);
367 static void catchsig(gint sig
)
374 if (global_client
->pinentry
->pid
) {
375 kill(SIGTERM
, global_client
->pinentry
->pid
);
376 global_client
->pinentry
->pid
= 0;
379 memset(&pk
, 0, sizeof(pk
));
380 pk
.error
= sig
== SIGTERM
? GPG_ERR_ASS_CANCELED
: GPG_ERR_TIMEOUT
;
381 pth_write(send_fd
, &pk
, sizeof(pk
));
382 cleanup_pinentry(global_client
->pinentry
);
383 free_client(global_client
);
389 gpg_error_t
pinentry_fork(assuan_context_t ctx
)
391 struct client_s
*client
= assuan_get_pointer(ctx
);
400 return gpg_error_from_syserror();
406 error
= gpg_error_from_syserror();
411 signal(SIGALRM
, catchsig
);
412 signal(SIGTERM
, catchsig
);
415 global_client
= client
;
416 alarm(client
->pinentry
->timeout
);
417 pk
.error
= getpin(client
->pinentry
, &result
);
418 cleanup_pinentry(client
->pinentry
);
423 len
= pth_write(p
[1], &pk
, sizeof(pk
));
426 if (len
!= sizeof(pk
))
427 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
433 strncpy(pk
.key
, result
, sizeof(pk
.key
));
435 len
= pth_write(p
[1], &pk
, sizeof(pk
));
436 memset(&pk
, 0, sizeof(pk
));
439 if (len
!= sizeof(pk
))
440 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
444 client
->pinentry
->fd
= p
[0];
445 client
->pinentry
->pid
= pid
;
446 client
->pinentry
->status
= PINENTRY_INIT
;
451 * Don't call assuan_process_done() here. That should be done in
452 * open_command_finalize() after the key has been read().
457 void cleanup_pinentry(struct pinentry_s
*pin
)
462 if (pin
->ctx
&& pin
->pid
)
463 pinentry_disconnect(pin
);
465 g_free(pin
->ttyname
);
466 g_free(pin
->ttytype
);
471 g_free(pin
->display
);
475 void set_pinentry_defaults(struct pinentry_s
*pin
)
479 struct passwd
*pw
= getpwuid(getuid());
482 g_snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", pw
->pw_dir
);
483 fp
= fopen(buf
, "r");
486 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
487 gchar name
[32] = {0}, value
[256] = {0};
492 if (p
[strlen(p
)-1] == '\n')
495 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, value
) != 2)
498 if (g_strcasecmp("TTYNAME", name
) == 0)
499 pin
->ttyname
= g_strdup(value
);
500 else if (g_strcasecmp("TTYTYPE", name
) == 0)
501 pin
->ttytype
= g_strdup(value
);
502 else if (g_strcasecmp("DISPLAY", name
) == 0)
503 pin
->display
= g_strdup(value
);
504 else if (g_strcasecmp("PATH", name
) == 0)
505 pin
->path
= g_strdup(value
);
511 pin
->use
= get_key_file_boolean("default", "enable_pinentry");