2 /* vim:tw=78:ts=8:sw=4:set ft=c: */
4 Copyright (C) 2007-2009 Ben Kibbey <bjk@luxsci.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
29 #include <sys/select.h>
42 #define N_(msgid) gettext(msgid)
46 #define DEFAULT_PORT 22
49 static void show_error(gpg_error_t error
)
51 fprintf(stderr
, "ERR %i %s\n", gpg_err_code(error
), pwmd_strerror(error
));
54 static void usage(const char *pn
)
57 "Reads PWMD protocol commands from standard input.\n\n"
58 "Usage: pwmc [-hvX] [-s <socket>] "
62 "[-PTNDCM <string>] [-p <passphrase>]\n"
63 " [-S [-i <iter>]] [-c <name>] [-t <n>] [-d <fd>] [-I <fd>]\n"
65 " [-H <hostname> [-R <port>] -Y <identity> -K <known_hosts>\n"
66 " -U <username> [-G]] [filename]\n"
71 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd nb)\n"
72 " -y number of pinentry tries before failing (3)\n"
75 " -H connect to hostname\n"
76 " -R alterate port (%i)\n"
78 " -Y SSH identity file\n"
79 " -K known host's file (for server validation)\n"
80 " -G retrieve the remote SSH host key and exit\n"
82 " -t pinentry timeout\n"
83 " -X disable showing of status messages from the server\n"
84 " -c set the client name\n"
85 " -s socket path (~/.pwmd/socket)\n"
87 " -P path to the pinentry binary (server default)\n"
89 " -N pinentry terminal type\n"
90 " -D pinentry display\n"
91 " -C pinentry LC_CTYPE\n"
92 " -M pinentry LC_MESSAGES\n"
93 " -d redirect command output to the specified file descriptor\n"
94 " -I read inquire data from the specified file descriptor\n"
95 " -S send the SAVE command before exiting\n"
96 " -i encrypt with the specified number of iterations\n"
98 " -h this help text\n"), DEFAULT_PORT
);
107 static gpg_error_t
do_inquire(void *data
, const char *keyword
, gpg_error_t rc
,
108 char **result
, size_t *result_len
)
111 static char buf
[ASSUAN_LINELENGTH
];
114 struct inquire_s
*inq
= (struct inquire_s
*)data
;
117 memset(buf
, 0, sizeof(buf
));
125 snprintf(buf
, sizeof(buf
), "%s", inq
->data
);
132 while ((c
= fgetc(inq
->fp
)) != EOF
) {
133 if (len
== sizeof(buf
)) {
143 memset(buf
, 0, sizeof(buf
));
152 static int status_msg_cb(void *data
, const char *line
)
154 fprintf(stderr
, "%s\n", line
);
159 static gpg_error_t
do_nb_command(int fd
, int which
)
162 gpg_error_t error
= 0;
164 fcntl(fd
, F_SETFL
, O_NONBLOCK
);
168 struct timeval tv
= {0, 50000};
172 n
= select(fd
+1, &fds
, NULL
, NULL
, &tv
);
175 if (FD_ISSET(fd
, &fds
)) {
176 pwmd_nb_status_t status
;
178 n
= read(fd
, &status
, sizeof(status
));
181 error
= gpg_error_from_errno(errno
);
186 error
= pwmd_open_nb_finalize(pwm
, &status
);
188 error
= pwmd_save_nb_finalize(pwm
, &status
);
203 int main(int argc
, char *argv
[])
206 char *password
= NULL
;
207 char *filename
= NULL
;
208 char *socketpath
= NULL
;
209 char command
[ASSUAN_LINELENGTH
], *p
;
210 int ret
= EXIT_SUCCESS
;
214 char *pinentry_path
= NULL
;
215 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
, *lcctype
= NULL
,
217 int outfd
= STDOUT_FILENO
;
218 FILE *outfp
= stdout
;
219 int inquirefd
= STDIN_FILENO
;
220 FILE *inquirefp
= stdin
;
222 char *clientname
= NULL
;
223 char *inquire
= NULL
;
229 int port
= DEFAULT_PORT
;
230 char *username
= NULL
;
232 char *known_hosts
= NULL
;
242 setlocale(LC_ALL
, "");
243 bindtextdomain("libpwmd", LOCALEDIR
);
248 while ((opt
= getopt(argc
, argv
, "C:M:GK:U:Y:H:R:y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
250 while ((opt
= getopt(argc
, argv
, "C:M:y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
254 while ((opt
= getopt(argc
, argv
, "C:M:GK:U:Y:H:R:t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
256 while ((opt
= getopt(argc
, argv
, "C:M:t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
262 method
= atoi(optarg
);
268 tries
= atoi(optarg
);
273 host
= xstrdup(optarg
);
279 ident
= xstrdup(optarg
);
282 username
= xstrdup(optarg
);
285 known_hosts
= xstrdup(optarg
);
292 lcctype
= xstrdup(optarg
);
295 lcmessages
= xstrdup(optarg
);
298 timeout
= atoi(optarg
);
301 clientname
= xstrdup(optarg
);
316 inquirefd
= atoi(optarg
);
317 inquirefp
= fdopen(inquirefd
, "r");
321 err(EXIT_FAILURE
, "%i", inquirefd
);
325 outfd
= atoi(optarg
);
326 outfp
= fdopen(outfd
, "w");
330 err(EXIT_FAILURE
, "%i", outfd
);
337 iter
= strtol(optarg
, NULL
, 10);
341 socketpath
= xstrdup(optarg
);
344 password
= xstrdup(optarg
);
345 memset(optarg
, 0, strlen(optarg
));
348 pinentry_path
= xstrdup(optarg
);
352 printf("%s (pwmc)\n%s\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
361 filename
= argv
[optind
];
372 pwm
= pwmd_get_hostkey_async(host
, port
, &error
);
375 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
378 s
= pwmd_process(pwm
, &error
);
381 } while (s
== ASYNC_PROCESS
);
385 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
388 error
= pwmd_get_result(pwm
, &hostkey
);
392 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
395 printf("%s\n", hostkey
);
401 if ((pwm
= pwmd_tcp_connect_async(host
, port
, ident
, username
, known_hosts
, &error
)) == NULL
) {
403 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
407 s
= pwmd_process(pwm
, &error
);
410 } while (s
== ASYNC_PROCESS
);
415 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
424 char *hostkey
= pwmd_get_hostkey(host
, port
, &error
);
427 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
429 printf("%s\n", hostkey
);
430 pwmd_free_result(hostkey
);
434 if ((pwm
= pwmd_tcp_connect(host
, port
, ident
, username
, known_hosts
, &error
)) == NULL
) {
436 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
444 if ((pwm
= pwmd_connect(socketpath
, &error
)) == NULL
) {
446 errx(EXIT_FAILURE
, "pwmd_connect(): %s", pwmd_strerror(error
));
452 error
= pwmd_command(pwm
, &result
, "OPTION CLIENT NAME=%s", clientname
? clientname
: "pwmc");
461 error
= pwmd_command(pwm
, &result
, "VERSION");
463 if (error
&& error
!= GPG_ERR_ASS_UNKNOWN_CMD
) {
468 pwmd_free_result(result
);
470 if (error
== GPG_ERR_ASS_UNKNOWN_CMD
) {
478 /* pwmd version 2 or later. */
488 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
497 error
= pwmd_setopt(pwm
, PWMD_OPTION_PASSWORD
, password
);
508 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
515 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
522 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
529 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
536 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
543 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
,
552 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY
, 1);
559 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
568 error
= pwmd_setopt(pwm
, PWMD_OPTION_STATUS_FUNC
, status_msg_cb
);
576 /* This method doesn't support PWMD_OPTION_PINENTRY_TRIES. */
578 error
= pwmd_open_async(pwm
, filename
);
582 s
= pwmd_process(pwm
, &error
);
585 } while (s
== ASYNC_PROCESS
);
590 else if (method
== 2) {
591 int fd
= pwmd_open_nb(pwm
, &error
, filename
, timeout
);
596 error
= do_nb_command(fd
, 0);
599 error
= pwmd_open(pwm
, filename
);
601 error
= pwmd_open(pwm
, filename
);
609 error
= pwmd_command(pwm
, &result
, "LOCK");
618 struct timeval tv
= {0, 100000};
623 FD_SET(STDIN_FILENO
, &rfds
);
624 n
= select(STDIN_FILENO
+1, &rfds
, NULL
, NULL
, &tv
);
627 s
= pwmd_process(pwm
, &error
);
632 fprintf(stderr
, ".");
637 error
= gpg_error_from_errno(errno
);
641 fprintf(stderr
, "\n");
642 n
= read(STDIN_FILENO
, command
, sizeof(command
));
645 error
= gpg_error_from_errno(errno
);
649 if (n
&& command
[strlen(command
)-1] == '\n')
650 command
[strlen(command
)-1] = 0;
658 p
= fgets(command
, sizeof(command
), stdin
);
660 p
= fgets(command
, sizeof(command
), stdin
);
667 * This is a known INQUIRE command. We use pwmd_inquire() to send the
668 * data from the do_inquire() callback function.
670 if (strncasecmp(p
, "STORE ", 6) == 0) {
672 inquire
= (char *)"STORE";
674 else if (strncasecmp(p
, "IMPORT ", 7) == 0) {
676 inquire
= (char *)"IMPORT";
680 struct inquire_s
*inq
= (struct inquire_s
*)malloc(sizeof(struct inquire_s
));
683 error
= gpg_error_from_errno(ENOMEM
);
687 inq
->data
= xstrdup(p
);
689 error
= pwmd_inquire(pwm
, inquire
, do_inquire
, inq
);
694 if (strcasecmp(p
, "BYE") == 0)
697 error
= pwmd_command(pwm
, &result
, command
);
698 memset(command
, 0, sizeof(command
));
704 fwrite(result
, 1, strlen(result
), outfp
);
705 pwmd_free_result(result
);
709 memset(command
, 0, sizeof(command
));
711 if (!error
&& save
) {
713 error
= pwmd_command(pwm
, &result
, "OPTION ITERATIONS=%i", iter
);
721 error
= pwmd_save_async(pwm
);
725 s
= pwmd_process(pwm
, &error
);
728 } while (s
== ASYNC_PROCESS
);
733 else if (method
== 3) {
734 int fd
= pwmd_save_nb(pwm
, &error
);
739 error
= do_nb_command(fd
, 1);
742 error
= pwmd_save(pwm
);
744 error
= pwmd_save(pwm
);
748 if (!error
&& filename
)
749 error
= pwmd_command(pwm
, &result
, "UNLOCK");