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"
43 static struct client_s
*global_client
;
46 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
);
48 static int mem_realloc_cb(void *data
, const void *buffer
, size_t len
)
50 membuf_t
*mem
= (membuf_t
*)data
;
56 if ((p
= xrealloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
60 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
65 static gpg_error_t
assuan_command(struct pinentry_s
*pin
, char **result
,
74 rc
= assuan_transact(pin
->ctx
, cmd
, mem_realloc_cb
, &data
, NULL
, NULL
,
85 mem_realloc_cb(&data
, "", 1);
86 *result
= (gchar
*)data
.buf
;
93 static gpg_error_t
launch_pinentry(struct pinentry_s
*pin
)
97 int child_list
[] = {-1};
98 char *display
= getenv("DISPLAY");
100 int have_display
= 0;
103 //update_pinentry_settings(pin);
105 if (pin
->display
|| display
)
108 tty
= pin
->ttyname
? pin
->ttyname
: ttyname(STDOUT_FILENO
);
111 return GPG_ERR_INV_VALUE
;
115 if (!have_display
&& !tty
)
116 return GPG_ERR_INV_VALUE
;
118 argv
[0] = "pinentry";
119 argv
[1] = have_display
? "--display" : "--ttyname";
120 argv
[2] = have_display
? pin
->display
? pin
->display
: display
: tty
;
124 gchar
*p
= getenv("TERM");
127 argv
[3] = "--ttytype";
128 argv
[4] = pin
->ttytype
? pin
->ttytype
: p
;
132 return GPG_ERR_INV_VALUE
;
135 rc
= assuan_pipe_connect(&ctx
, pin
->path
? pin
->path
: PINENTRY_PATH
,
141 pin
->pid
= assuan_get_pid(ctx
);
143 return set_pinentry_strings(pin
, 0);
146 static gpg_error_t
pinentry_command(struct pinentry_s
*pin
, gchar
**result
,
149 gpg_error_t error
= 0;
152 error
= launch_pinentry(pin
);
154 return error
? error
: assuan_command(pin
, result
, cmd
);
157 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
)
164 title
= g_strdup(N_("Password mismatch, please try again."));
165 else if (!pin
->title
)
166 title
= pin
->title
= g_strdup(N_("Password Manager Daemon"));
171 pin
->prompt
= g_strdup(N_("Password:"));
173 if (!pin
->desc
&& !which
)
174 pin
->desc
= g_strdup_printf(pin
->which
== PINENTRY_OPEN
?
175 N_("A password is required to open the file \"%s\". Please%%0Aenter the password below.") :
176 N_("A password is required to save to the file \"%s\". Please%%0Aenter the password below."),
180 buf
= g_strdup_printf("SETERROR %s", N_("Please type the password again for confirmation."));
182 buf
= g_strdup_printf("SETERROR %s", pin
->desc
);
184 error
= pinentry_command(pin
, NULL
, buf
);
190 buf
= g_strdup_printf("SETPROMPT %s", pin
->prompt
);
191 error
= pinentry_command(pin
, NULL
, buf
);
197 buf
= g_strdup_printf("SETDESC %s", title
);
198 error
= pinentry_command(pin
, NULL
, buf
);
208 static void pinentry_disconnect(struct pinentry_s
*pin
)
214 assuan_disconnect(pin
->ctx
);
220 static gpg_error_t
do_getpin(struct pinentry_s
*pin
, char **result
)
225 error
= pinentry_command(pin
, result
, "GETPIN");
228 *result
= xstrdup("");
233 static gpg_error_t
getpin(struct pinentry_s
*pin
, gchar
**result
)
236 gpg_error_t error
= set_pinentry_strings(pin
, which
);
237 gchar
*result1
= NULL
;
240 pinentry_disconnect(pin
);
245 error
= do_getpin(pin
, result
);
250 if (pin
->which
== PINENTRY_SAVE
) {
252 error
= set_pinentry_strings(pin
, 2);
257 result1
= g_strdup(*result
);
261 if (strcmp(result1
, *result
)) {
264 result1
= *result
= NULL
;
265 error
= set_pinentry_strings(pin
, 1);
276 pinentry_disconnect(pin
);
280 static void catchsig(gint sig
)
287 memset(&pk
, 0, sizeof(pk
));
288 pk
.error
= sig
== SIGTERM
? GPG_ERR_ASS_CANCELED
: GPG_ERR_TIMEOUT
;
289 pth_write(send_fd
, &pk
, sizeof(pk
));
291 cleanup_pinentry(global_client
->pinentry
);
292 free_client(global_client
);
298 gpg_error_t
pinentry_fork(assuan_context_t ctx
)
300 struct client_s
*client
= assuan_get_pointer(ctx
);
309 return gpg_error_from_syserror();
315 error
= gpg_error_from_syserror();
320 signal(SIGALRM
, catchsig
);
321 signal(SIGTERM
, catchsig
);
324 global_client
= client
;
325 alarm(client
->pinentry
->timeout
);
326 pk
.error
= getpin(client
->pinentry
, &result
);
327 cleanup_pinentry(client
->pinentry
);
332 len
= pth_write(p
[1], &pk
, sizeof(pk
));
335 if (len
!= sizeof(pk
))
336 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
342 strncpy(pk
.key
, result
, sizeof(pk
.key
));
344 len
= pth_write(p
[1], &pk
, sizeof(pk
));
345 memset(&pk
, 0, sizeof(pk
));
348 if (len
!= sizeof(pk
))
349 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
354 client
->pinentry
->fd
= p
[0];
355 client
->pinentry
->pid
= pid
;
356 client
->pinentry
->status
= PINENTRY_INIT
;
361 * Don't call assuan_process_done() here. That should be done in
362 * open_command_finalize() after the key has been read().
367 void cleanup_pinentry(struct pinentry_s
*pin
)
372 if (pin
->ctx
&& pin
->pid
)
373 pinentry_disconnect(pin
);
375 g_free(pin
->ttyname
);
376 g_free(pin
->ttytype
);
381 g_free(pin
->display
);
385 void set_pinentry_defaults(struct pinentry_s
*pin
)
389 struct passwd
*pw
= getpwuid(getuid());
392 g_snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", pw
->pw_dir
);
393 fp
= fopen(buf
, "r");
396 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
397 gchar name
[32] = {0}, value
[256] = {0};
402 if (p
[strlen(p
)-1] == '\n')
405 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, value
) != 2)
408 if (g_strcasecmp("TTYNAME", name
) == 0)
409 pin
->ttyname
= g_strdup(value
);
410 else if (g_strcasecmp("TTYTYPE", name
) == 0)
411 pin
->ttytype
= g_strdup(value
);
412 else if (g_strcasecmp("DISPLAY", name
) == 0)
413 pin
->display
= g_strdup(value
);
414 else if (g_strcasecmp("PATH", name
) == 0)
415 pin
->path
= g_strdup(value
);
421 pin
->use
= get_key_file_boolean("default", "enable_pinentry");