1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2007-2008 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
33 #include "pwmd_error.h"
40 void free_client_list();
41 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
);
43 static int mem_realloc_cb(void *data
, const void *buffer
, size_t len
)
45 membuf_t
*mem
= (membuf_t
*)data
;
51 if ((p
= xrealloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
55 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
60 static gpg_error_t
assuan_command(struct pinentry_s
*pin
, gchar
**result
,
69 rc
= assuan_transact(pin
->ctx
, cmd
, mem_realloc_cb
, &data
, NULL
, NULL
,
80 mem_realloc_cb(&data
, "", 1);
81 *result
= (gchar
*)data
.buf
;
88 static gpg_error_t
set_pinentry_options(struct pinentry_s
*pin
)
90 gchar
*display
= getenv("DISPLAY");
91 gint have_display
= 0;
92 gchar
*tty
= NULL
, *ttytype
= NULL
;
96 gchar cmd
[ASSUAN_LINELENGTH
];
98 if (pin
->display
|| display
)
101 tty
= pin
->ttyname
? pin
->ttyname
: ttyname(STDOUT_FILENO
);
104 return GPG_ERR_CANCELED
;
107 if (!have_display
&& !tty
)
108 return GPG_ERR_CANCELED
;
111 gchar
*p
= getenv("TERM");
113 ttytype
= pin
->ttytype
? pin
->ttytype
: p
;
116 return GPG_ERR_CANCELED
;
119 opt
= have_display
? "DISPLAY" : "TTYNAME";
120 val
= have_display
? pin
->display
? pin
->display
: display
: tty
;
121 g_snprintf(cmd
, sizeof(cmd
), "OPTION %s=%s", g_ascii_strdown(opt
, strlen(opt
)), val
);
122 rc
= assuan_command(pin
, &result
, cmd
);
128 g_snprintf(cmd
, sizeof(cmd
), "OPTION ttytype=%s", ttytype
);
129 rc
= assuan_command(pin
, &result
, cmd
);
135 static gpg_error_t
launch_pinentry(struct pinentry_s
*pin
)
138 assuan_context_t ctx
;
139 gint child_list
[] = {-1};
140 const gchar
*argv
[] = { "pinentry", NULL
};
142 rc
= assuan_pipe_connect(&ctx
, pin
->path
? pin
->path
: PINENTRY_PATH
,
148 pin
->pid
= assuan_get_pid(ctx
);
150 rc
= set_pinentry_options(pin
);
151 return rc
? rc
: set_pinentry_strings(pin
, 0);
154 static gpg_error_t
pinentry_command(struct pinentry_s
*pin
, gchar
**result
,
160 rc
= launch_pinentry(pin
);
162 return rc
? rc
: assuan_command(pin
, result
, cmd
);
165 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
)
172 title
= g_strdup(N_("Password mismatch, please try again."));
173 else if (!pin
->title
)
174 title
= pin
->title
= g_strdup(N_("Password Manager Daemon"));
179 pin
->prompt
= g_strdup(N_("Password:"));
181 if (!pin
->desc
&& !which
)
182 pin
->desc
= g_strdup_printf(pin
->which
== PINENTRY_OPEN
?
183 N_("A password is required to open the file \"%s\". Please%%0Aenter the password below.") :
184 N_("A password is required to save to the file \"%s\". Please%%0Aenter the password below."),
188 buf
= g_strdup_printf("SETERROR %s", N_("Please type the password again for confirmation."));
190 buf
= g_strdup_printf("SETERROR %s", pin
->desc
);
192 rc
= pinentry_command(pin
, NULL
, buf
);
198 buf
= g_strdup_printf("SETPROMPT %s", pin
->prompt
);
199 rc
= pinentry_command(pin
, NULL
, buf
);
205 buf
= g_strdup_printf("SETDESC %s", title
);
206 rc
= pinentry_command(pin
, NULL
, buf
);
216 static void pinentry_disconnect(struct pinentry_s
*pin
)
222 assuan_disconnect(pin
->ctx
);
228 static gpg_error_t
do_getpin(struct pinentry_s
*pin
, char **result
)
233 rc
= pinentry_command(pin
, result
, "GETPIN");
236 *result
= xstrdup("");
241 gpg_error_t
pinentry_getpin(struct pinentry_s
*pin
, gchar
**result
)
244 gpg_error_t rc
= set_pinentry_strings(pin
, which
);
245 gchar
*result1
= NULL
;
248 pinentry_disconnect(pin
);
253 rc
= do_getpin(pin
, result
);
258 if (pin
->which
== PINENTRY_SAVE
) {
260 rc
= set_pinentry_strings(pin
, 2);
265 result1
= g_strdup(*result
);
269 if (strcmp(result1
, *result
)) {
272 result1
= *result
= NULL
;
273 rc
= set_pinentry_strings(pin
, 1);
284 pinentry_disconnect(pin
);
288 gpg_error_t
pinentry_fork(assuan_context_t ctx
)
290 struct client_s
*client
= assuan_get_pointer(ctx
);
291 struct pinentry_s
*pin
= client
->pinentry
;
297 gchar
*result
= NULL
;
300 return gpg_error_from_syserror();
306 rc
= gpg_error_from_syserror();
313 pk
.error
= pinentry_getpin(pin
, &result
);
319 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
320 * will disconnect the client even if the error isn't related
321 * to it. Use GPG_ERR_CANCELED instead.
323 if (gpg_err_code(pk
.error
) == GPG_ERR_EOF
)
324 pk
.error
= GPG_ERR_CANCELED
;
326 len
= pth_write(p
[1], &pk
, sizeof(pk
));
329 if (len
!= sizeof(pk
))
330 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
336 g_strlcpy(pk
.key
, result
, sizeof(pk
.key
));
338 len
= pth_write(p
[1], &pk
, sizeof(pk
));
339 memset(&pk
, 0, sizeof(pk
));
342 if (len
!= sizeof(pk
))
343 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
348 client
->pinentry
->fd
= p
[0];
349 client
->pinentry
->pid
= pid
;
350 client
->pinentry
->status
= PINENTRY_INIT
;
355 * Don't call assuan_process_done() here. That should be done in
356 * open_command_finalize() after the key has been read().
361 void lock_pin_mutex(struct client_s
*client
)
363 if (pth_mutex_acquire(&pin_mutex
, TRUE
, NULL
) == FALSE
) {
365 assuan_write_status(client
->ctx
, "LOCKED", N_("Waiting for lock"));
367 pth_mutex_acquire(&pin_mutex
, FALSE
, NULL
);
370 client
->pinentry
->has_lock
= TRUE
;
373 void unlock_pin_mutex(struct pinentry_s
*pin
)
375 if (pin
->has_lock
== FALSE
)
378 pth_mutex_release(&pin_mutex
);
379 pin
->has_lock
= FALSE
;
382 void cleanup_pinentry(struct pinentry_s
*pin
)
387 unlock_pin_mutex(pin
);
389 if (pin
->ctx
&& pin
->pid
)
390 pinentry_disconnect(pin
);
392 g_free(pin
->ttyname
);
393 g_free(pin
->ttytype
);
398 g_free(pin
->display
);
399 g_free(pin
->filename
);
403 void set_pinentry_defaults(struct pinentry_s
*pin
)
407 struct passwd
*pw
= getpwuid(getuid());
410 g_snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", pw
->pw_dir
);
411 fp
= fopen(buf
, "r");
414 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
415 gchar name
[32] = {0}, value
[256] = {0};
420 if (p
[strlen(p
)-1] == '\n')
423 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, value
) != 2)
426 if (g_strcasecmp("TTYNAME", name
) == 0)
427 pin
->ttyname
= g_strdup(value
);
428 else if (g_strcasecmp("TTYTYPE", name
) == 0)
429 pin
->ttytype
= g_strdup(value
);
430 else if (g_strcasecmp("DISPLAY", name
) == 0)
431 pin
->display
= g_strdup(value
);
432 else if (g_strcasecmp("PATH", name
) == 0)
433 pin
->path
= g_strdup(value
);