1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2009 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 02110-1301 USA
19 #include <sys/types.h>
28 static gpg_error_t
set_pinentry_strings(pwm_t
*pwm
, int which
);
30 static void update_pinentry_settings(pwm_t
*pwm
)
36 char *pwbuf
= _getpwuid(&pw
);
41 snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", pw
.pw_dir
);
43 if ((fp
= fopen(buf
, "r")) == NULL
) {
48 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
49 char name
[32], val
[256];
51 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, val
) != 2)
54 if (strcasecmp(name
, "TTYNAME") == 0) {
55 pwmd_free(pwm
->pinentry_tty
);
56 pwm
->pinentry_tty
= pwmd_strdup(val
);
58 else if (strcasecmp(name
, "TTYTYPE") == 0) {
59 pwmd_free(pwm
->pinentry_term
);
60 pwm
->pinentry_term
= pwmd_strdup(val
);
62 else if (strcasecmp(name
, "DISPLAY") == 0) {
63 pwmd_free(pwm
->pinentry_display
);
64 pwm
->pinentry_display
= pwmd_strdup(val
);
66 else if (strcasecmp(name
, "PATH") == 0) {
67 pwmd_free(pwm
->pinentry_path
);
68 pwm
->pinentry_path
= _expand_homedir(val
, &pw
);
76 static gpg_error_t
launch_pinentry(pwm_t
*pwm
)
80 int child_list
[] = {-1};
81 char *display
= getenv("DISPLAY");
83 const char **p
= argv
;
88 update_pinentry_settings(pwm
);
90 if (pwm
->pinentry_display
|| display
)
93 if (!pwm
->pinentry_tty
) {
94 ttybuf
= pwmd_malloc(255);
97 return gpg_error_from_errno(ENOMEM
);
99 rc
= ttyname_r(STDOUT_FILENO
, ttybuf
, 255);
103 return gpg_error_from_errno(rc
);
109 tty
= pwm
->pinentry_tty
;
112 if (!have_display
&& !tty
)
113 return GPG_ERR_ENOTTY
;
116 *p
++ = have_display
? "--display" : "--ttyname";
117 *p
++ = have_display
? pwm
->pinentry_display
? pwm
->pinentry_display
: display
: tty
;
124 if (pwm
->lcmessages
) {
125 *p
++ = "--lc-messages";
126 *p
++ = pwm
->lcmessages
;
133 *p
++ = pwm
->pinentry_term
? pwm
->pinentry_term
: getenv("TERM");
137 rc
= assuan_pipe_connect(&ctx
, pwm
->pinentry_path
? pwm
->pinentry_path
: PINENTRY_PATH
, argv
, child_list
);
145 pwm
->pid
= assuan_get_pid(ctx
);
147 return set_pinentry_strings(pwm
, 0);
150 static gpg_error_t
pinentry_command(pwm_t
*pwm
, char **result
, const char *cmd
)
153 gpg_error_t rc
= launch_pinentry(pwm
);
156 return gpg_err_code(rc
);
159 return _assuan_command(pwm
, pwm
->pctx
, result
, cmd
);
162 static gpg_error_t
set_pinentry_strings(pwm_t
*pwm
, int which
)
164 char *tmp
, *desc
= NULL
;
167 tmp
= pwmd_malloc(ASSUAN_LINELENGTH
+1);
170 return gpg_error_from_errno(ENOMEM
);
173 pwm
->title
= pwmd_strdup_printf(N_("Password Manager Daemon: %s"),
174 pwm
->name
? pwm
->name
: "libpwmd");
180 pwm
->prompt
= pwmd_strdup(N_("Passphrase:"));
185 if (!pwm
->desc
&& (which
== PINENTRY_OPEN
|| which
== PINENTRY_SAVE
)) {
186 if (which
== PINENTRY_OPEN
)
187 desc
= pwmd_strdup_printf(N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below."), pwm
->filename
);
189 desc
= pwmd_strdup_printf(N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."), pwm
->filename
);
201 snprintf(tmp
, ASSUAN_LINELENGTH
, "SETERROR %s", desc
);
203 if (pwm
->desc
!= desc
)
206 case PINENTRY_OPEN_FAILED
:
207 snprintf(tmp
, ASSUAN_LINELENGTH
, "SETERROR %s",
208 N_("Invalid passphrase, please try again."));
210 case PINENTRY_SAVE_CONFIRM
:
211 snprintf(tmp
, ASSUAN_LINELENGTH
, "SETERROR %s",
212 N_("Please type the passphrase again for confirmation."));
216 error
= pinentry_command(pwm
, NULL
, tmp
);
223 snprintf(tmp
, ASSUAN_LINELENGTH
, "SETPROMPT %s", pwm
->prompt
);
224 error
= pinentry_command(pwm
, NULL
, tmp
);
231 snprintf(tmp
, ASSUAN_LINELENGTH
, "SETDESC %s", pwm
->title
);
232 error
= pinentry_command(pwm
, NULL
, tmp
);
238 return gpg_error_from_errno(ENOMEM
);
241 static gpg_error_t
terminate_pinentry(pwm_t
*pwm
)
243 pid_t pid
= pwm
->pid
;
247 if (!pwm
|| pid
== -1)
248 return GPG_ERR_INV_ARG
;
250 if (kill(pid
, 0) == 0) {
251 if (kill(pid
, SIGTERM
) == -1) {
252 if (kill(pid
, SIGKILL
) == -1)
253 return gpg_error_from_errno(errno
);
257 return gpg_error_from_errno(errno
);
262 void _pinentry_disconnect(pwm_t
*pwm
)
265 assuan_disconnect(pwm
->pctx
);
272 * Only called from a child process.
274 static void catchsig(int sig
)
278 if (gelapsed
++ >= gtimeout
) {
279 terminate_pinentry(gpwm
);
280 gerror
= GPG_ERR_TIMEOUT
;
290 static gpg_error_t
do_getpin(pwm_t
*pwm
, char **result
)
293 signal(SIGALRM
, catchsig
);
298 return pinentry_command(pwm
, result
, "GETPIN");
301 gpg_error_t
_getpin(pwm_t
*pwm
, char **result
, int which
)
306 rc
= set_pinentry_strings(pwm
, which
);
309 _pinentry_disconnect(pwm
);
313 rc
= do_getpin(pwm
, result
);
316 * Since there was input cancel any timeout setting.
319 signal(SIGALRM
, SIG_DFL
);
323 _pinentry_disconnect(pwm
);
325 /* This lets pwmd_open2() with PWMD_OPTION_PINENTRY_TIMEOUT work. */
326 if (rc
== GPG_ERR_EOF
&& gerror
== GPG_ERR_TIMEOUT
)
335 gpg_error_t
_do_save_getpin(pwm_t
*pwm
, char **password
)
342 error
= _getpin(pwm
, &result
, confirm
? PINENTRY_SAVE_CONFIRM
: PINENTRY_SAVE
);
346 _pinentry_disconnect(pwm
);
349 pwmd_free(*password
);
359 if (strcmp(*password
, result
)) {
360 pwmd_free(*password
);
368 _pinentry_disconnect(pwm
);