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
38 #define N_(msgid) gettext(msgid)
44 #define xrealloc realloc
45 #define xmalloc malloc
46 #define xstrdup strdup
47 #define xcalloc calloc
53 static void show_error(gpg_error_t error
)
55 fprintf(stderr
, "ERR %i %s\n", gpg_err_code(error
), pwmd_strerror(error
));
58 void catchsig(int sig
)
64 if (pwm
&& timeout
> 0 && elapsed
++ >= timeout
) {
65 error
= pwmd_terminate_pinentry(pwm
);
80 static void usage(const char *pn
)
83 "Reads PWMD protocol commands from standard input.\n\n"
84 "Usage: pwmc [-hvX] [-s <socket>] [[-a [-P -T -N -D] [-t <seconds>]] |\n"
85 " [-p <password>]] [-S] [-d <n>] [-I <n>] [filename]\n"
86 " -X disable showing of status messages from the server\n"
89 " -a use pinentry(1) for password retrieval\n"
90 " -P path to the pinentry binary (%s)\n"
92 " -N pinentry terminal type\n"
93 " -D pinentry display\n"
94 " -t pinentry timeout\n"
95 " -d redirect command output to the specified file descriptor\n"
96 " -I read inquire data from the specified file descriptor\n"
97 " -S send the SAVE command after all others\n"
99 " -h this help text\n"), PINENTRY_PATH
);
103 int set_pinentry_option(pwmd_option_t option
, void *value
)
107 error
= pwmd_setopt(pwm
, option
, value
);
123 static int do_inquire(void *data
, const char *keyword
, gpg_error_t rc
,
124 char **result
, size_t *result_len
)
127 static char buf
[1000]; /* Assuan protocol line length limit. */
130 struct inquire_s
*inq
= data
;
133 memset(buf
, 0, sizeof(buf
));
138 return EPWMD_COMMAND_SYNTAX
;
144 snprintf(buf
, sizeof(buf
), "%s", inq
->data
);
151 while ((c
= fgetc(inq
->fp
)) != EOF
) {
152 if (len
>= sizeof(buf
)) {
162 memset(buf
, 0, sizeof(buf
));
172 static int status_msg_cb(void *data
, const char *line
)
174 fprintf(stderr
, "%s\n", line
);
178 int main(int argc
, char *argv
[])
181 int use_pinentry
= 0;
182 char *password
= NULL
;
183 char *filename
= NULL
;
184 char *socketpath
= NULL
;
185 char command
[1000], *p
;
186 int ret
= EXIT_SUCCESS
;
190 char *pinentry_path
= NULL
;
191 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
193 int outfd
= STDOUT_FILENO
;
194 FILE *outfp
= stdout
;
195 int inquirefd
= STDIN_FILENO
;
196 FILE *inquirefp
= stdin
;
199 setlocale(LC_ALL
, "");
200 bindtextdomain("libpwmd", LOCALEDIR
);
203 while ((opt
= getopt(argc
, argv
, "I:XT:N:D:hvaP:t:p:s:Sd:")) != EOF
) {
218 inquirefd
= atoi(optarg
);
219 inquirefp
= fdopen(inquirefd
, "r");
223 err(EXIT_FAILURE
, "%i", inquirefd
);
227 outfd
= atoi(optarg
);
228 outfp
= fdopen(outfd
, "w");
232 err(EXIT_FAILURE
, "%i", outfd
);
239 socketpath
= xstrdup(optarg
);
242 password
= xstrdup(optarg
);
248 pinentry_path
= xstrdup(optarg
);
251 timeout
= atoi(optarg
);
255 printf("%s (pwmc)\n%s\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
264 if (use_pinentry
&& password
) {
269 filename
= argv
[optind
];
272 if ((pwm
= pwmd_connect(socketpath
, &error
)) == NULL
) {
274 errx(EXIT_FAILURE
, "pwmd_connect(): %s", pwmd_strerror(error
));
278 if (set_pinentry_option(PWMD_OPTION_PASSWORD
, password
)) {
285 else if (use_pinentry
) {
286 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY
, 1);
294 if (set_pinentry_option(PWMD_OPTION_PINENTRY_PATH
, pinentry_path
))
297 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TITLE
,
298 N_("Password Manager Daemon")))
301 snprintf(command
, sizeof(command
), N_("A password is required for the "
302 "file \"%s\". Please\nenter the password below."), filename
);
304 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DESC
, command
))
308 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DISPLAY
, display
))
313 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TTY
, tty
))
318 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TERM
, ttytype
))
323 if (set_pinentry_option(PWMD_OPTION_INQUIRE_FUNC
, do_inquire
)) {
330 if (set_pinentry_option(PWMD_OPTION_STATUS_FUNC
, status_msg_cb
)) {
338 if (use_pinentry
&& timeout
!= -1) {
339 tcgetattr(STDOUT_FILENO
, &term
);
340 signal(SIGALRM
, catchsig
);
344 error
= pwmd_open(pwm
, filename
);
347 if (error
== GPG_ERR_TIMEOUT
) {
348 tcsetattr(STDOUT_FILENO
, 0, &term
);
358 signal(SIGALRM
, SIG_IGN
);
361 p
= fgets(command
, sizeof(command
), stdin
);
366 if (strncasecmp(p
, "STORE ", 6) == 0) {
367 struct inquire_s
*inq
= malloc(sizeof(struct inquire_s
));
369 inq
->data
= xstrdup(p
+6);
372 if (set_pinentry_option(PWMD_OPTION_INQUIRE_DATA
, inq
)) {
379 error
= pwmd_command(pwm
, &result
, "STORE");
387 memset(command
, 0, sizeof(command
));
391 if (p
[strlen(p
) - 1] == '\n')
392 p
[strlen(p
) - 1] = 0;
394 if (strcasecmp(p
, "BYE") == 0)
397 error
= pwmd_command(pwm
, &result
, command
);
398 memset(command
, 0, sizeof(command
));
407 if (isatty(outfd
) && result
[strlen(result
) - 1] == '\n')
408 result
[strlen(result
) - 1] = 0;
410 fwrite(result
, 1, strlen(result
), outfp
);
411 pwmd_free_result(result
);
418 memset(command
, 0, sizeof(command
));
422 error
= pwmd_save(pwm
);
425 if (use_pinentry
&& (error
== EPWMD_BADKEY
|| error
== EPWMD_KEY
))