1 /*
2 * Unix Pageant, more or less similar to ssh-agent.
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <assert.h>
9 #include <signal.h>
10 #include <ctype.h>
11
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <termios.h>
18
19 #include "putty.h"
20 #include "ssh.h"
21 #include "misc.h"
22 #include "pageant.h"
23
cmdline_error(const char * fmt,...)24 void cmdline_error(const char *fmt, ...)
25 {
26 va_list ap;
27 va_start(ap, fmt);
28 console_print_error_msg_fmt_v("pageant", fmt, ap);
29 va_end(ap);
30 exit(1);
31 }
32
33 static void setup_sigchld_handler(void);
34
35 typedef enum RuntimePromptType {
36 RTPROMPT_UNAVAILABLE,
37 RTPROMPT_DEBUG,
38 RTPROMPT_GUI,
39 } RuntimePromptType;
40
41 static const char *progname;
42
43 struct uxpgnt_client {
44 FILE *logfp;
45 strbuf *prompt_buf;
46 RuntimePromptType prompt_type;
47 bool prompt_active;
48 PageantClientDialogId *dlgid;
49 int passphrase_fd;
50 int termination_pid;
51
52 PageantListenerClient plc;
53 };
54
uxpgnt_log(PageantListenerClient * plc,const char * fmt,va_list ap)55 static void uxpgnt_log(PageantListenerClient *plc, const char *fmt, va_list ap)
56 {
57 struct uxpgnt_client *upc = container_of(plc, struct uxpgnt_client, plc);
58
59 if (!upc->logfp)
60 return;
61
62 fprintf(upc->logfp, "pageant: ");
63 vfprintf(upc->logfp, fmt, ap);
64 fprintf(upc->logfp, "\n");
65 }
66
make_pipe_to_askpass(const char * msg)67 static int make_pipe_to_askpass(const char *msg)
68 {
69 int pipefds[2];
70
71 setup_sigchld_handler();
72
73 if (pipe(pipefds) < 0)
74 return -1;
75
76 pid_t pid = fork();
77 if (pid < 0) {
78 close(pipefds[0]);
79 close(pipefds[1]);
80 return -1;
81 }
82
83 if (pid == 0) {
84 const char *args[5] = {
85 progname, "--gui-prompt", "--askpass", msg, NULL
86 };
87
88 dup2(pipefds[1], 1);
89 cloexec(pipefds[0]);
90 cloexec(pipefds[1]);
91
92 /*
93 * See comment in fork_and_exec_self() in gtkmain.c.
94 */
95 execv("/proc/self/exe", (char **)args);
96 execvp(progname, (char **)args);
97 perror("exec");
98 _exit(127);
99 }
100
101 close(pipefds[1]);
102 return pipefds[0];
103 }
104
uxpgnt_ask_passphrase(PageantListenerClient * plc,PageantClientDialogId * dlgid,const char * comment)105 static bool uxpgnt_ask_passphrase(
106 PageantListenerClient *plc, PageantClientDialogId *dlgid,
107 const char *comment)
108 {
109 struct uxpgnt_client *upc = container_of(plc, struct uxpgnt_client, plc);
110
111 assert(!upc->dlgid); /* Pageant core should be serialising requests */
112
113 char *msg = dupprintf(
114 "A client of Pageant wants to use the following encrypted key:\n"
115 "%s\n"
116 "If you intended this, enter the passphrase to decrypt the key.",
117 comment);
118
119 switch (upc->prompt_type) {
120 case RTPROMPT_UNAVAILABLE:
121 sfree(msg);
122 return false;
123
124 case RTPROMPT_GUI:
125 upc->passphrase_fd = make_pipe_to_askpass(msg);
126 sfree(msg);
127 if (upc->passphrase_fd < 0)
128 return false; /* something went wrong */
129 break;
130
131 case RTPROMPT_DEBUG:
132 fprintf(upc->logfp, "pageant passphrase request: %s\n", msg);
133 sfree(msg);
134 break;
135 }
136
137 upc->prompt_active = true;
138 upc->dlgid = dlgid;
139 return true;
140 }
141
passphrase_done(struct uxpgnt_client * upc,bool success)142 static void passphrase_done(struct uxpgnt_client *upc, bool success)
143 {
144 PageantClientDialogId *dlgid = upc->dlgid;
145 upc->dlgid = NULL;
146 upc->prompt_active = false;
147
148 if (upc->logfp)
149 fprintf(upc->logfp, "pageant passphrase response: %s\n",
150 success ? "success" : "failure");
151
152 if (success)
153 pageant_passphrase_request_success(
154 dlgid, ptrlen_from_strbuf(upc->prompt_buf));
155 else
156 pageant_passphrase_request_refused(dlgid);
157
158 strbuf_free(upc->prompt_buf);
159 upc->prompt_buf = strbuf_new_nm();
160 }
161
162 static const PageantListenerClientVtable uxpgnt_vtable = {
163 .log = uxpgnt_log,
164 .ask_passphrase = uxpgnt_ask_passphrase,
165 };
166
167 /*
168 * More stubs.
169 */
random_save_seed(void)170 void random_save_seed(void) {}
random_destroy_seed(void)171 void random_destroy_seed(void) {}
platform_default_s(const char * name)172 char *platform_default_s(const char *name) { return NULL; }
platform_default_b(const char * name,bool def)173 bool platform_default_b(const char *name, bool def) { return def; }
platform_default_i(const char * name,int def)174 int platform_default_i(const char *name, int def) { return def; }
platform_default_fontspec(const char * name)175 FontSpec *platform_default_fontspec(const char *name) { return fontspec_new(""); }
platform_default_filename(const char * name)176 Filename *platform_default_filename(const char *name) { return filename_from_str(""); }
x_get_default(const char * key)177 char *x_get_default(const char *key) { return NULL; }
178
179 /*
180 * Short description of parameters.
181 */
usage(void)182 static void usage(void)
183 {
184 printf("Pageant: SSH agent\n");
185 printf("%s\n", ver);
186 printf("Usage: pageant <lifetime> [[--encrypted] key files]\n");
187 printf(" pageant [[--encrypted] key files] --exec <command> [args]\n");
188 printf(" pageant -a [--encrypted] [key files]\n");
189 printf(" pageant -d [key identifiers]\n");
190 printf(" pageant -D\n");
191 printf(" pageant -r [key identifiers]\n");
192 printf(" pageant -R\n");
193 printf(" pageant --public [key identifiers]\n");
194 printf(" pageant ( --public-openssh | -L ) [key identifiers]\n");
195 printf(" pageant -l [-E fptype]\n");
196 printf("Lifetime options, for running Pageant as an agent:\n");
197 printf(" -X run with the lifetime of the X server\n");
198 printf(" -T run with the lifetime of the controlling tty\n");
199 printf(" --permanent run permanently\n");
200 printf(" --debug run in debugging mode, without forking\n");
201 printf(" --exec <command> run with the lifetime of that command\n");
202 printf("Client options, for talking to an existing agent:\n");
203 printf(" -a add key(s) to the existing agent\n");
204 printf(" -l list currently loaded key fingerprints and comments\n");
205 printf(" --public print public keys in RFC 4716 format\n");
206 printf(" --public-openssh, -L print public keys in OpenSSH format\n");
207 printf(" -d delete key(s) from the agent\n");
208 printf(" -D delete all keys from the agent\n");
209 printf(" -r re-encrypt keys in the agent (forget cleartext\n");
210 printf(" -R re-encrypt all possible keys in the agent\n");
211 printf("Other options:\n");
212 printf(" -v verbose mode (in agent mode)\n");
213 printf(" -s -c force POSIX or C shell syntax (in agent mode)\n");
214 printf(" --symlink path create symlink to socket (in agent mode)\n");
215 printf(" --encrypted when adding keys, don't decrypt\n");
216 printf(" -E alg, --fptype alg fingerprint type for -l (sha256, md5)\n");
217 printf(" --tty-prompt force tty-based passphrase prompt\n");
218 printf(" --gui-prompt force GUI-based passphrase prompt\n");
219 printf(" --askpass <prompt> behave like a standalone askpass program\n");
220 exit(1);
221 }
222
version(void)223 static void version(void)
224 {
225 char *buildinfo_text = buildinfo("\n");
226 printf("pageant: %s\n%s\n", ver, buildinfo_text);
227 sfree(buildinfo_text);
228 exit(0);
229 }
230
keylist_update(void)231 void keylist_update(void)
232 {
233 /* Nothing needs doing in Unix Pageant */
234 }
235
236 #define PAGEANT_DIR_PREFIX "/tmp/pageant"
237
238 const char *const appname = "Pageant";
239
240 static bool time_to_die = false;
241
242 /* Stub functions to permit linking against x11fwd.c. These never get
243 * used, because in LIFE_X11 mode we connect to the X server using a
244 * straightforward Socket and don't try to create an ersatz SSH
245 * forwarding too. */
chan_remotely_opened_confirmation(Channel * chan)246 void chan_remotely_opened_confirmation(Channel *chan) { }
chan_remotely_opened_failure(Channel * chan,const char * err)247 void chan_remotely_opened_failure(Channel *chan, const char *err) { }
chan_default_want_close(Channel * chan,bool s,bool r)248 bool chan_default_want_close(Channel *chan, bool s, bool r) { return false; }
chan_no_exit_status(Channel * ch,int s)249 bool chan_no_exit_status(Channel *ch, int s) { return false; }
chan_no_exit_signal(Channel * ch,ptrlen s,bool c,ptrlen m)250 bool chan_no_exit_signal(Channel *ch, ptrlen s, bool c, ptrlen m)
251 { return false; }
chan_no_exit_signal_numeric(Channel * ch,int s,bool c,ptrlen m)252 bool chan_no_exit_signal_numeric(Channel *ch, int s, bool c, ptrlen m)
253 { return false; }
chan_no_run_shell(Channel * chan)254 bool chan_no_run_shell(Channel *chan) { return false; }
chan_no_run_command(Channel * chan,ptrlen command)255 bool chan_no_run_command(Channel *chan, ptrlen command) { return false; }
chan_no_run_subsystem(Channel * chan,ptrlen subsys)256 bool chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return false; }
chan_no_enable_x11_forwarding(Channel * chan,bool oneshot,ptrlen authproto,ptrlen authdata,unsigned screen_number)257 bool chan_no_enable_x11_forwarding(
258 Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata,
259 unsigned screen_number) { return false; }
chan_no_enable_agent_forwarding(Channel * chan)260 bool chan_no_enable_agent_forwarding(Channel *chan) { return false; }
chan_no_allocate_pty(Channel * chan,ptrlen termtype,unsigned width,unsigned height,unsigned pixwidth,unsigned pixheight,struct ssh_ttymodes modes)261 bool chan_no_allocate_pty(
262 Channel *chan, ptrlen termtype, unsigned width, unsigned height,
263 unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes)
264 { return false; }
chan_no_set_env(Channel * chan,ptrlen var,ptrlen value)265 bool chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return false; }
chan_no_send_break(Channel * chan,unsigned length)266 bool chan_no_send_break(Channel *chan, unsigned length) { return false; }
chan_no_send_signal(Channel * chan,ptrlen signame)267 bool chan_no_send_signal(Channel *chan, ptrlen signame) { return false; }
chan_no_change_window_size(Channel * chan,unsigned width,unsigned height,unsigned pixwidth,unsigned pixheight)268 bool chan_no_change_window_size(
269 Channel *chan, unsigned width, unsigned height,
270 unsigned pixwidth, unsigned pixheight) { return false; }
chan_no_request_response(Channel * chan,bool success)271 void chan_no_request_response(Channel *chan, bool success) {}
272
273 /*
274 * These functions are part of the plug for our connection to the X
275 * display, so they do get called. They needn't actually do anything,
276 * except that x11_closing has to signal back to the main loop that
277 * it's time to terminate.
278 */
x11_log(Plug * p,PlugLogType type,SockAddr * addr,int port,const char * error_msg,int error_code)279 static void x11_log(Plug *p, PlugLogType type, SockAddr *addr, int port,
280 const char *error_msg, int error_code) {}
x11_receive(Plug * plug,int urgent,const char * data,size_t len)281 static void x11_receive(Plug *plug, int urgent, const char *data, size_t len) {}
x11_sent(Plug * plug,size_t bufsize)282 static void x11_sent(Plug *plug, size_t bufsize) {}
x11_closing(Plug * plug,const char * error_msg,int error_code,bool calling_back)283 static void x11_closing(Plug *plug, const char *error_msg, int error_code,
284 bool calling_back)
285 {
286 time_to_die = true;
287 }
288 struct X11Connection {
289 Plug plug;
290 };
291
292 static char *socketname;
293 static enum { SHELL_AUTO, SHELL_SH, SHELL_CSH } shell_type = SHELL_AUTO;
pageant_print_env(int pid)294 void pageant_print_env(int pid)
295 {
296 if (shell_type == SHELL_AUTO) {
297 /* Same policy as OpenSSH: if $SHELL ends in "csh" then assume
298 * it's csh-shaped. */
299 const char *shell = getenv("SHELL");
300 if (shell && strlen(shell) >= 3 &&
301 !strcmp(shell + strlen(shell) - 3, "csh"))
302 shell_type = SHELL_CSH;
303 else
304 shell_type = SHELL_SH;
305 }
306
307 /*
308 * These shell snippets could usefully pay some attention to
309 * escaping of interesting characters. I don't think it causes a
310 * problem at the moment, because the pathnames we use are so
311 * utterly boring, but it's a lurking bug waiting to happen once
312 * a bit more flexibility turns up.
313 */
314
315 switch (shell_type) {
316 case SHELL_SH:
317 printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n"
318 "SSH_AGENT_PID=%d; export SSH_AGENT_PID;\n",
319 socketname, pid);
320 break;
321 case SHELL_CSH:
322 printf("setenv SSH_AUTH_SOCK %s;\n"
323 "setenv SSH_AGENT_PID %d;\n",
324 socketname, pid);
325 break;
326 case SHELL_AUTO:
327 unreachable("SHELL_AUTO should have been eliminated by now");
328 break;
329 }
330 }
331
pageant_fork_and_print_env(bool retain_tty)332 void pageant_fork_and_print_env(bool retain_tty)
333 {
334 pid_t pid = fork();
335 if (pid == -1) {
336 perror("fork");
337 exit(1);
338 } else if (pid != 0) {
339 pageant_print_env(pid);
340 exit(0);
341 }
342
343 /*
344 * Having forked off, we now daemonise ourselves as best we can.
345 * It's good practice in general to setsid() ourself out of any
346 * process group we didn't want to be part of, and to chdir("/")
347 * to avoid holding any directories open that we don't need in
348 * case someone wants to umount them; also, we should definitely
349 * close standard output (because it will very likely be pointing
350 * at a pipe from which some parent process is trying to read our
351 * environment variable dump, so if we hold open another copy of
352 * it then that process will never finish reading). We close
353 * standard input too on general principles, but not standard
354 * error, since we might need to shout a panicky error message
355 * down that one.
356 */
357 if (chdir("/") < 0) {
358 /* should there be an error condition, nothing we can do about
359 * it anyway */
360 }
361 close(0);
362 close(1);
363 if (retain_tty) {
364 /* Get out of our previous process group, to avoid being
365 * blasted by passing signals. But keep our controlling tty,
366 * so we can keep checking to see if we still have one. */
367 setpgrp(0,0);
368 } else {
369 /* Do that, but also leave our entire session and detach from
370 * the controlling tty (if any). */
371 setsid();
372 }
373 }
374
375 static int signalpipe[2] = { -1, -1 };
376
sigchld(int signum)377 static void sigchld(int signum)
378 {
379 if (write(signalpipe[1], "x", 1) <= 0)
380 /* not much we can do about it */;
381 }
382
setup_sigchld_handler(void)383 static void setup_sigchld_handler(void)
384 {
385 if (signalpipe[0] >= 0)
386 return;
387
388 /*
389 * Set up the pipe we'll use to tell us about SIGCHLD.
390 */
391 if (pipe(signalpipe) < 0) {
392 perror("pipe");
393 exit(1);
394 }
395 putty_signal(SIGCHLD, sigchld);
396 }
397
398 #define TTY_LIFE_POLL_INTERVAL (TICKSPERSEC * 30)
399 static void *dummy_timer_ctx;
tty_life_timer(void * ctx,unsigned long now)400 static void tty_life_timer(void *ctx, unsigned long now)
401 {
402 schedule_timer(TTY_LIFE_POLL_INTERVAL, tty_life_timer, &dummy_timer_ctx);
403 }
404
405 typedef enum {
406 KEYACT_AGENT_LOAD,
407 KEYACT_AGENT_LOAD_ENCRYPTED,
408 KEYACT_CLIENT_BASE,
409 KEYACT_CLIENT_ADD = KEYACT_CLIENT_BASE,
410 KEYACT_CLIENT_ADD_ENCRYPTED,
411 KEYACT_CLIENT_DEL,
412 KEYACT_CLIENT_DEL_ALL,
413 KEYACT_CLIENT_LIST,
414 KEYACT_CLIENT_PUBLIC_OPENSSH,
415 KEYACT_CLIENT_PUBLIC,
416 KEYACT_CLIENT_SIGN,
417 KEYACT_CLIENT_REENCRYPT,
418 KEYACT_CLIENT_REENCRYPT_ALL,
419 } keyact;
420 struct cmdline_key_action {
421 struct cmdline_key_action *next;
422 keyact action;
423 const char *filename;
424 };
425
is_agent_action(keyact action)426 bool is_agent_action(keyact action)
427 {
428 return action < KEYACT_CLIENT_BASE;
429 }
430
431 static struct cmdline_key_action *keyact_head = NULL, *keyact_tail = NULL;
432 static uint32_t sign_flags = 0;
433
add_keyact(keyact action,const char * filename)434 void add_keyact(keyact action, const char *filename)
435 {
436 struct cmdline_key_action *a = snew(struct cmdline_key_action);
437 a->action = action;
438 a->filename = filename;
439 a->next = NULL;
440 if (keyact_tail)
441 keyact_tail->next = a;
442 else
443 keyact_head = a;
444 keyact_tail = a;
445 }
446
have_controlling_tty(void)447 bool have_controlling_tty(void)
448 {
449 int fd = open("/dev/tty", O_RDONLY);
450 if (fd < 0) {
451 if (errno != ENXIO) {
452 perror("/dev/tty: open");
453 exit(1);
454 }
455 return false;
456 } else {
457 close(fd);
458 return true;
459 }
460 }
461
462 static char **exec_args = NULL;
463 static enum {
464 LIFE_UNSPEC, LIFE_X11, LIFE_TTY, LIFE_DEBUG, LIFE_PERM, LIFE_EXEC
465 } life = LIFE_UNSPEC;
466 static const char *display = NULL;
467 static enum {
468 PROMPT_UNSPEC, PROMPT_TTY, PROMPT_GUI
469 } prompt_type = PROMPT_UNSPEC;
470 static FingerprintType key_list_fptype = SSH_FPTYPE_DEFAULT;
471
askpass_tty(const char * prompt)472 static char *askpass_tty(const char *prompt)
473 {
474 int ret;
475 prompts_t *p = new_prompts();
476 p->to_server = false;
477 p->from_server = false;
478 p->name = dupstr("Pageant passphrase prompt");
479 add_prompt(p, dupcat(prompt, ": "), false);
480 ret = console_get_userpass_input(p);
481 assert(ret >= 0);
482
483 if (!ret) {
484 perror("pageant: unable to read passphrase");
485 free_prompts(p);
486 return NULL;
487 } else {
488 char *passphrase = prompt_get_result(p->prompts[0]);
489 free_prompts(p);
490 return passphrase;
491 }
492 }
493
askpass_gui(const char * prompt)494 static char *askpass_gui(const char *prompt)
495 {
496 char *passphrase;
497 bool success;
498
499 passphrase = gtk_askpass_main(
500 display, "Pageant passphrase prompt", prompt, &success);
501 if (!success) {
502 /* return value is error message */
503 fprintf(stderr, "%s\n", passphrase);
504 sfree(passphrase);
505 passphrase = NULL;
506 }
507 return passphrase;
508 }
509
askpass(const char * prompt)510 static char *askpass(const char *prompt)
511 {
512 if (prompt_type == PROMPT_TTY) {
513 if (!have_controlling_tty()) {
514 fprintf(stderr, "no controlling terminal available "
515 "for passphrase prompt\n");
516 return NULL;
517 }
518 return askpass_tty(prompt);
519 }
520
521 if (prompt_type == PROMPT_GUI) {
522 if (!display) {
523 fprintf(stderr, "no graphical display available "
524 "for passphrase prompt\n");
525 return NULL;
526 }
527 return askpass_gui(prompt);
528 }
529
530 if (have_controlling_tty()) {
531 return askpass_tty(prompt);
532 } else if (display) {
533 return askpass_gui(prompt);
534 } else {
535 fprintf(stderr, "no way to read a passphrase without tty or "
536 "X display\n");
537 return NULL;
538 }
539 }
540
unix_add_keyfile(const char * filename_str,bool add_encrypted)541 static bool unix_add_keyfile(const char *filename_str, bool add_encrypted)
542 {
543 Filename *filename = filename_from_str(filename_str);
544 int status;
545 bool ret;
546 char *err;
547
548 ret = true;
549
550 /*
551 * Try without a passphrase.
552 */
553 status = pageant_add_keyfile(filename, NULL, &err, add_encrypted);
554 if (status == PAGEANT_ACTION_OK) {
555 goto cleanup;
556 } else if (status == PAGEANT_ACTION_FAILURE) {
557 fprintf(stderr, "pageant: %s: %s\n", filename_str, err);
558 ret = false;
559 goto cleanup;
560 }
561
562 /*
563 * And now try prompting for a passphrase.
564 */
565 while (1) {
566 char *prompt = dupprintf(
567 "Enter passphrase to load key '%s'", err);
568 char *passphrase = askpass(prompt);
569 sfree(err);
570 sfree(prompt);
571 err = NULL;
572 if (!passphrase)
573 break;
574
575 status = pageant_add_keyfile(filename, passphrase, &err,
576 add_encrypted);
577
578 smemclr(passphrase, strlen(passphrase));
579 sfree(passphrase);
580 passphrase = NULL;
581
582 if (status == PAGEANT_ACTION_OK) {
583 goto cleanup;
584 } else if (status == PAGEANT_ACTION_FAILURE) {
585 fprintf(stderr, "pageant: %s: %s\n", filename_str, err);
586 ret = false;
587 goto cleanup;
588 }
589 }
590
591 cleanup:
592 sfree(err);
593 filename_free(filename);
594 return ret;
595 }
596
key_list_callback(void * ctx,char ** fingerprints,const char * comment,uint32_t ext_flags,struct pageant_pubkey * key)597 void key_list_callback(void *ctx, char **fingerprints, const char *comment,
598 uint32_t ext_flags, struct pageant_pubkey *key)
599 {
600 const char *mode = "";
601 if (ext_flags & LIST_EXTENDED_FLAG_HAS_NO_CLEARTEXT_KEY)
602 mode = " (encrypted)";
603 else if (ext_flags & LIST_EXTENDED_FLAG_HAS_ENCRYPTED_KEY_FILE)
604 mode = " (re-encryptable)";
605
606 FingerprintType this_type =
607 ssh2_pick_fingerprint(fingerprints, key_list_fptype);
608 printf("%s %s%s\n", fingerprints[this_type], comment, mode);
609 }
610
611 struct key_find_ctx {
612 const char *string;
613 bool match_fp, match_comment;
614 bool match_fptypes[SSH_N_FPTYPES];
615 struct pageant_pubkey *found;
616 int nfound;
617 };
618
match_fingerprint_string(const char * string_orig,char ** fingerprints,const struct key_find_ctx * ctx)619 static bool match_fingerprint_string(
620 const char *string_orig, char **fingerprints,
621 const struct key_find_ctx *ctx)
622 {
623 const char *hash;
624
625 for (unsigned fptype = 0; fptype < SSH_N_FPTYPES; fptype++) {
626 if (!ctx->match_fptypes[fptype])
627 continue;
628
629 const char *fingerprint = fingerprints[fptype];
630 if (!fingerprint)
631 continue;
632
633 /* Find the hash in the fingerprint string. It'll be the word
634 * at the end. */
635 hash = strrchr(fingerprint, ' ');
636 assert(hash);
637 hash++;
638
639 const char *string = string_orig;
640 bool case_sensitive;
641 const char *ignore_chars = "";
642
643 switch (fptype) {
644 case SSH_FPTYPE_MD5:
645 /* MD5 fingerprints are in hex, so disregard case differences. */
646 case_sensitive = false;
647 /* And we don't really need to force the user to type the
648 * colons in between the digits, which are always the
649 * same. */
650 ignore_chars = ":";
651 break;
652 case SSH_FPTYPE_SHA256:
653 /* Skip over the "SHA256:" prefix, which we don't really
654 * want to force the user to type. On the other hand,
655 * tolerate it on the input string. */
656 assert(strstartswith(hash, "SHA256:"));
657 hash += 7;
658 if (strstartswith(string, "SHA256:"))
659 string += 7;
660 /* SHA256 fingerprints are base64, which is intrinsically
661 * case sensitive. */
662 case_sensitive = true;
663 break;
664 }
665
666 /* Now see if the search string is a prefix of the full hash,
667 * neglecting colons and (where appropriate) case differences. */
668 while (1) {
669 string += strspn(string, ignore_chars);
670 hash += strspn(hash, ignore_chars);
671 if (!*string)
672 return true;
673 char sc = *string, hc = *hash;
674 if (!case_sensitive) {
675 sc = tolower((unsigned char)sc);
676 hc = tolower((unsigned char)hc);
677 }
678 if (sc != hc)
679 break;
680 string++;
681 hash++;
682 }
683 }
684
685 return false;
686 }
687
key_find_callback(void * vctx,char ** fingerprints,const char * comment,uint32_t ext_flags,struct pageant_pubkey * key)688 void key_find_callback(void *vctx, char **fingerprints,
689 const char *comment, uint32_t ext_flags,
690 struct pageant_pubkey *key)
691 {
692 struct key_find_ctx *ctx = (struct key_find_ctx *)vctx;
693
694 if ((ctx->match_comment && !strcmp(ctx->string, comment)) ||
695 (ctx->match_fp && match_fingerprint_string(ctx->string, fingerprints,
696 ctx)))
697 {
698 if (!ctx->found)
699 ctx->found = pageant_pubkey_copy(key);
700 ctx->nfound++;
701 }
702 }
703
find_key(const char * string,char ** retstr)704 struct pageant_pubkey *find_key(const char *string, char **retstr)
705 {
706 struct key_find_ctx ctx[1];
707 struct pageant_pubkey key_in, *key_ret;
708 bool try_file = true, try_fp = true, try_comment = true;
709 bool file_errors = false;
710 bool try_all_fptypes = true;
711 FingerprintType fptype = SSH_FPTYPE_DEFAULT;
712
713 /*
714 * Trim off disambiguating prefixes telling us how to interpret
715 * the provided string.
716 */
717 if (!strncmp(string, "file:", 5)) {
718 string += 5;
719 try_fp = false;
720 try_comment = false;
721 file_errors = true; /* also report failure to load the file */
722 } else if (!strncmp(string, "comment:", 8)) {
723 string += 8;
724 try_file = false;
725 try_fp = false;
726 } else if (!strncmp(string, "fp:", 3)) {
727 string += 3;
728 try_file = false;
729 try_comment = false;
730 } else if (!strncmp(string, "fingerprint:", 12)) {
731 string += 12;
732 try_file = false;
733 try_comment = false;
734 } else if (!strnicmp(string, "md5:", 4)) {
735 string += 4;
736 try_file = false;
737 try_comment = false;
738 try_all_fptypes = false;
739 fptype = SSH_FPTYPE_MD5;
740 } else if (!strncmp(string, "sha256:", 7)) {
741 string += 7;
742 try_file = false;
743 try_comment = false;
744 try_all_fptypes = false;
745 fptype = SSH_FPTYPE_SHA256;
746 }
747
748 /*
749 * Try interpreting the string as a key file name.
750 */
751 if (try_file) {
752 Filename *fn = filename_from_str(string);
753 int keytype = key_type(fn);
754 if (keytype == SSH_KEYTYPE_SSH1 ||
755 keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
756 const char *error;
757
758 key_in.blob = strbuf_new();
759 if (!rsa1_loadpub_f(fn, BinarySink_UPCAST(key_in.blob),
760 NULL, &error)) {
761 strbuf_free(key_in.blob);
762 key_in.blob = NULL;
763 if (file_errors) {
764 *retstr = dupprintf("unable to load file '%s': %s",
765 string, error);
766 filename_free(fn);
767 return NULL;
768 }
769 } else {
770 /*
771 * If we've successfully loaded the file, stop here - we
772 * already have a key blob and need not go to the agent to
773 * list things.
774 */
775 key_in.ssh_version = 1;
776 key_in.comment = NULL;
777 key_ret = pageant_pubkey_copy(&key_in);
778 strbuf_free(key_in.blob);
779 key_in.blob = NULL;
780 filename_free(fn);
781 return key_ret;
782 }
783 } else if (keytype == SSH_KEYTYPE_SSH2 ||
784 keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||
785 keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
786 const char *error;
787
788 key_in.blob = strbuf_new();
789 if (!ppk_loadpub_f(fn, NULL, BinarySink_UPCAST(key_in.blob),
790 NULL, &error)) {
791 strbuf_free(key_in.blob);
792 key_in.blob = NULL;
793 if (file_errors) {
794 *retstr = dupprintf("unable to load file '%s': %s",
795 string, error);
796 filename_free(fn);
797 return NULL;
798 }
799 } else {
800 /*
801 * If we've successfully loaded the file, stop here - we
802 * already have a key blob and need not go to the agent to
803 * list things.
804 */
805 key_in.ssh_version = 2;
806 key_in.comment = NULL;
807 key_ret = pageant_pubkey_copy(&key_in);
808 strbuf_free(key_in.blob);
809 key_in.blob = NULL;
810 filename_free(fn);
811 return key_ret;
812 }
813 } else {
814 if (file_errors) {
815 *retstr = dupprintf("unable to load key file '%s': %s",
816 string, key_type_to_str(keytype));
817 filename_free(fn);
818 return NULL;
819 }
820 }
821 filename_free(fn);
822 }
823
824 /*
825 * Failing that, go through the keys in the agent, and match
826 * against fingerprints and comments as appropriate.
827 */
828 ctx->string = string;
829 ctx->match_fp = try_fp;
830 ctx->match_comment = try_comment;
831 for (unsigned i = 0; i < SSH_N_FPTYPES; i++)
832 ctx->match_fptypes[i] = (try_all_fptypes || i == fptype);
833 ctx->found = NULL;
834 ctx->nfound = 0;
835 if (pageant_enum_keys(key_find_callback, ctx, retstr) ==
836 PAGEANT_ACTION_FAILURE)
837 return NULL;
838
839 if (ctx->nfound == 0) {
840 *retstr = dupstr("no key matched");
841 assert(!ctx->found);
842 return NULL;
843 } else if (ctx->nfound > 1) {
844 *retstr = dupstr("multiple keys matched");
845 assert(ctx->found);
846 pageant_pubkey_free(ctx->found);
847 return NULL;
848 }
849
850 assert(ctx->found);
851 return ctx->found;
852 }
853
run_client(void)854 void run_client(void)
855 {
856 const struct cmdline_key_action *act;
857 struct pageant_pubkey *key;
858 bool errors = false;
859 char *retstr;
860 LoadedFile *message = lf_new(AGENT_MAX_MSGLEN);
861 bool message_loaded = false, message_ok = false;
862 strbuf *signature = strbuf_new();
863
864 if (!agent_exists()) {
865 fprintf(stderr, "pageant: no agent running to talk to\n");
866 exit(1);
867 }
868
869 for (act = keyact_head; act; act = act->next) {
870 switch (act->action) {
871 case KEYACT_CLIENT_ADD:
872 case KEYACT_CLIENT_ADD_ENCRYPTED:
873 if (!unix_add_keyfile(act->filename,
874 act->action == KEYACT_CLIENT_ADD_ENCRYPTED))
875 errors = true;
876 break;
877 case KEYACT_CLIENT_LIST:
878 if (pageant_enum_keys(key_list_callback, NULL, &retstr) ==
879 PAGEANT_ACTION_FAILURE) {
880 fprintf(stderr, "pageant: listing keys: %s\n", retstr);
881 sfree(retstr);
882 errors = true;
883 }
884 break;
885 case KEYACT_CLIENT_DEL:
886 key = NULL;
887 if (!(key = find_key(act->filename, &retstr)) ||
888 pageant_delete_key(key, &retstr) == PAGEANT_ACTION_FAILURE) {
889 fprintf(stderr, "pageant: deleting key '%s': %s\n",
890 act->filename, retstr);
891 sfree(retstr);
892 errors = true;
893 }
894 if (key)
895 pageant_pubkey_free(key);
896 break;
897 case KEYACT_CLIENT_REENCRYPT:
898 key = NULL;
899 if (!(key = find_key(act->filename, &retstr)) ||
900 pageant_reencrypt_key(key, &retstr) == PAGEANT_ACTION_FAILURE) {
901 fprintf(stderr, "pageant: re-encrypting key '%s': %s\n",
902 act->filename, retstr);
903 sfree(retstr);
904 errors = true;
905 }
906 if (key)
907 pageant_pubkey_free(key);
908 break;
909 case KEYACT_CLIENT_PUBLIC_OPENSSH:
910 case KEYACT_CLIENT_PUBLIC:
911 key = NULL;
912 if (!(key = find_key(act->filename, &retstr))) {
913 fprintf(stderr, "pageant: finding key '%s': %s\n",
914 act->filename, retstr);
915 sfree(retstr);
916 errors = true;
917 } else {
918 FILE *fp = stdout; /* FIXME: add a -o option? */
919
920 if (key->ssh_version == 1) {
921 BinarySource src[1];
922 RSAKey rkey;
923
924 BinarySource_BARE_INIT(src, key->blob->u, key->blob->len);
925 memset(&rkey, 0, sizeof(rkey));
926 rkey.comment = dupstr(key->comment);
927 get_rsa_ssh1_pub(src, &rkey, RSA_SSH1_EXPONENT_FIRST);
928 ssh1_write_pubkey(fp, &rkey);
929 freersakey(&rkey);
930 } else {
931 ssh2_write_pubkey(fp, key->comment,
932 key->blob->u,
933 key->blob->len,
934 (act->action == KEYACT_CLIENT_PUBLIC ?
935 SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 :
936 SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH));
937 }
938 pageant_pubkey_free(key);
939 }
940 break;
941 case KEYACT_CLIENT_DEL_ALL:
942 if (pageant_delete_all_keys(&retstr) == PAGEANT_ACTION_FAILURE) {
943 fprintf(stderr, "pageant: deleting all keys: %s\n", retstr);
944 sfree(retstr);
945 errors = true;
946 }
947 break;
948 case KEYACT_CLIENT_REENCRYPT_ALL: {
949 int status = pageant_reencrypt_all_keys(&retstr);
950 if (status == PAGEANT_ACTION_FAILURE) {
951 fprintf(stderr, "pageant: re-encrypting all keys: "
952 "%s\n", retstr);
953 sfree(retstr);
954 errors = true;
955 } else if (status == PAGEANT_ACTION_WARNING) {
956 fprintf(stderr, "pageant: re-encrypting all keys: "
957 "warning: %s\n", retstr);
958 sfree(retstr);
959 }
960 break;
961 }
962 case KEYACT_CLIENT_SIGN:
963 key = NULL;
964 if (!message_loaded) {
965 message_loaded = true;
966 switch(lf_load_fp(message, stdin)) {
967 case LF_TOO_BIG:
968 fprintf(stderr, "pageant: message to sign is too big\n");
969 errors = true;
970 break;
971 case LF_ERROR:
972 fprintf(stderr, "pageant: reading message to sign: %s\n",
973 strerror(errno));
974 errors = true;
975 break;
976 case LF_OK:
977 message_ok = true;
978 break;
979 }
980 }
981 if (!message_ok)
982 break;
983 strbuf_clear(signature);
984 if (!(key = find_key(act->filename, &retstr)) ||
985 pageant_sign(key, ptrlen_from_lf(message), signature,
986 sign_flags, &retstr) == PAGEANT_ACTION_FAILURE) {
987 fprintf(stderr, "pageant: signing with key '%s': %s\n",
988 act->filename, retstr);
989 sfree(retstr);
990 errors = true;
991 } else {
992 fwrite(signature->s, 1, signature->len, stdout);
993 }
994 if (key)
995 pageant_pubkey_free(key);
996 break;
997 default:
998 unreachable("Invalid client action found");
999 }
1000 }
1001
1002 lf_free(message);
1003 strbuf_free(signature);
1004
1005 if (errors)
1006 exit(1);
1007 }
1008
1009 static const PlugVtable X11Connection_plugvt = {
1010 .log = x11_log,
1011 .closing = x11_closing,
1012 .receive = x11_receive,
1013 .sent = x11_sent,
1014 };
1015
1016
agent_loop_pw_setup(void * vctx,pollwrapper * pw)1017 static bool agent_loop_pw_setup(void *vctx, pollwrapper *pw)
1018 {
1019 struct uxpgnt_client *upc = (struct uxpgnt_client *)vctx;
1020
1021 if (signalpipe[0] >= 0) {
1022 pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
1023 }
1024
1025 if (upc->prompt_active)
1026 pollwrap_add_fd_rwx(pw, upc->passphrase_fd, SELECT_R);
1027
1028 return true;
1029 }
1030
agent_loop_pw_check(void * vctx,pollwrapper * pw)1031 static void agent_loop_pw_check(void *vctx, pollwrapper *pw)
1032 {
1033 struct uxpgnt_client *upc = (struct uxpgnt_client *)vctx;
1034
1035 if (life == LIFE_TTY) {
1036 /*
1037 * Every time we wake up (whether it was due to tty_timer
1038 * elapsing or for any other reason), poll to see if we still
1039 * have a controlling terminal. If we don't, then our
1040 * containing tty session has ended, so it's time to clean up
1041 * and leave.
1042 */
1043 if (!have_controlling_tty()) {
1044 time_to_die = true;
1045 return;
1046 }
1047 }
1048
1049 if (signalpipe[0] >= 0 &&
1050 pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
1051 char c[1];
1052 if (read(signalpipe[0], c, 1) <= 0)
1053 /* ignore error */;
1054 /* ignore its value; it'll be `x' */
1055 while (1) {
1056 int status;
1057 pid_t pid;
1058 pid = waitpid(-1, &status, WNOHANG);
1059 if (pid <= 0)
1060 break;
1061 if (pid == upc->termination_pid)
1062 time_to_die = true;
1063 }
1064 }
1065
1066 if (upc->prompt_active &&
1067 pollwrap_check_fd_rwx(pw, upc->passphrase_fd, SELECT_R)) {
1068 char c;
1069 int retd = read(upc->passphrase_fd, &c, 1);
1070
1071 switch (upc->prompt_type) {
1072 case RTPROMPT_GUI:
1073 if (retd <= 0) {
1074 close(upc->passphrase_fd);
1075 upc->passphrase_fd = -1;
1076 bool ok = (retd == 0);
1077 if (!strbuf_chomp(upc->prompt_buf, '\n'))
1078 ok = false;
1079 passphrase_done(upc, ok);
1080 } else {
1081 put_byte(upc->prompt_buf, c);
1082 }
1083 break;
1084 case RTPROMPT_DEBUG:
1085 if (retd <= 0) {
1086 passphrase_done(upc, false);
1087 /* Now never try to read from stdin again */
1088 upc->prompt_type = RTPROMPT_UNAVAILABLE;
1089 break;
1090 }
1091
1092 switch (c) {
1093 case '\n':
1094 case '\r':
1095 passphrase_done(upc, true);
1096 break;
1097 case '\004':
1098 passphrase_done(upc, false);
1099 break;
1100 case '\b':
1101 case '\177':
1102 strbuf_shrink_by(upc->prompt_buf, 1);
1103 break;
1104 case '\025':
1105 strbuf_clear(upc->prompt_buf);
1106 break;
1107 default:
1108 put_byte(upc->prompt_buf, c);
1109 break;
1110 }
1111 break;
1112 case RTPROMPT_UNAVAILABLE:
1113 unreachable("Should never have started a prompt at all");
1114 }
1115 }
1116 }
1117
agent_loop_continue(void * vctx,bool fd,bool cb)1118 static bool agent_loop_continue(void *vctx, bool fd, bool cb)
1119 {
1120 return !time_to_die;
1121 }
1122
run_agent(FILE * logfp,const char * symlink_path)1123 void run_agent(FILE *logfp, const char *symlink_path)
1124 {
1125 const char *err;
1126 char *errw;
1127 struct pageant_listen_state *pl;
1128 Plug *pl_plug;
1129 Socket *sock;
1130 bool errors = false;
1131 Conf *conf;
1132 const struct cmdline_key_action *act;
1133
1134 pageant_init();
1135
1136 /*
1137 * Start by loading any keys provided on the command line.
1138 */
1139 for (act = keyact_head; act; act = act->next) {
1140 assert(act->action == KEYACT_AGENT_LOAD ||
1141 act->action == KEYACT_AGENT_LOAD_ENCRYPTED);
1142 if (!unix_add_keyfile(act->filename,
1143 act->action == KEYACT_AGENT_LOAD_ENCRYPTED))
1144 errors = true;
1145 }
1146 if (errors)
1147 exit(1);
1148
1149 /*
1150 * Set up a listening socket and run Pageant on it.
1151 */
1152 struct uxpgnt_client upc[1];
1153 memset(upc, 0, sizeof(upc));
1154 upc->plc.vt = &uxpgnt_vtable;
1155 upc->logfp = logfp;
1156 upc->passphrase_fd = -1;
1157 upc->termination_pid = -1;
1158 upc->prompt_buf = strbuf_new_nm();
1159 upc->prompt_type = display ? RTPROMPT_GUI : RTPROMPT_UNAVAILABLE;
1160 pl = pageant_listener_new(&pl_plug, &upc->plc);
1161 sock = platform_make_agent_socket(pl_plug, PAGEANT_DIR_PREFIX,
1162 &errw, &socketname);
1163 if (!sock) {
1164 fprintf(stderr, "pageant: %s\n", errw);
1165 sfree(errw);
1166 exit(1);
1167 }
1168 pageant_listener_got_socket(pl, sock);
1169
1170 if (symlink_path) {
1171 /*
1172 * Try to make a symlink to the Unix socket, in a location of
1173 * the user's choosing.
1174 *
1175 * If the link already exists, we want to replace it. There
1176 * are two ways we could do this: either make it under another
1177 * name and then rename it over the top, or remove the old
1178 * link first. The former is what 'ln -sf' does, on the
1179 * grounds that it's more atomic. But I think in this case,
1180 * where the expected use case is that the previous agent has
1181 * long since shut down, atomicity isn't a critical concern
1182 * compared to not accidentally overwriting some non-symlink
1183 * that might have important data in it!
1184 */
1185 struct stat st;
1186 if (lstat(symlink_path, &st) == 0 && S_ISLNK(st.st_mode))
1187 unlink(symlink_path);
1188 if (symlink(socketname, symlink_path) < 0)
1189 fprintf(stderr, "pageant: making symlink %s: %s\n",
1190 symlink_path, strerror(errno));
1191 }
1192
1193 conf = conf_new();
1194 conf_set_int(conf, CONF_proxy_type, PROXY_NONE);
1195
1196 /*
1197 * Lifetime preparations.
1198 */
1199 if (life == LIFE_X11) {
1200 struct X11Display *disp;
1201 void *greeting;
1202 int greetinglen;
1203 Socket *s;
1204 struct X11Connection *conn;
1205 char *x11_setup_err;
1206
1207 if (!display) {
1208 fprintf(stderr, "pageant: no DISPLAY for -X mode\n");
1209 exit(1);
1210 }
1211 disp = x11_setup_display(display, conf, &x11_setup_err);
1212 if (!disp) {
1213 fprintf(stderr, "pageant: unable to connect to X server: %s\n",
1214 x11_setup_err);
1215 sfree(x11_setup_err);
1216 exit(1);
1217 }
1218
1219 conn = snew(struct X11Connection);
1220 conn->plug.vt = &X11Connection_plugvt;
1221 s = new_connection(sk_addr_dup(disp->addr),
1222 disp->realhost, disp->port,
1223 false, true, false, false, &conn->plug, conf);
1224 if ((err = sk_socket_error(s)) != NULL) {
1225 fprintf(stderr, "pageant: unable to connect to X server: %s", err);
1226 exit(1);
1227 }
1228 greeting = x11_make_greeting('B', 11, 0, disp->localauthproto,
1229 disp->localauthdata,
1230 disp->localauthdatalen,
1231 NULL, 0, &greetinglen);
1232 sk_write(s, greeting, greetinglen);
1233 smemclr(greeting, greetinglen);
1234 sfree(greeting);
1235
1236 pageant_fork_and_print_env(false);
1237 } else if (life == LIFE_TTY) {
1238 schedule_timer(TTY_LIFE_POLL_INTERVAL,
1239 tty_life_timer, &dummy_timer_ctx);
1240 pageant_fork_and_print_env(true);
1241 } else if (life == LIFE_PERM) {
1242 pageant_fork_and_print_env(false);
1243 } else if (life == LIFE_DEBUG) {
1244 pageant_print_env(getpid());
1245 upc->logfp = stdout;
1246
1247 struct termios orig_termios;
1248 upc->passphrase_fd = fileno(stdin);
1249 if (tcgetattr(upc->passphrase_fd, &orig_termios) == 0) {
1250 struct termios new_termios = orig_termios;
1251 new_termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
1252
1253 /*
1254 * Try to set up a watchdog process that will restore
1255 * termios if we crash or are killed. If successful, turn
1256 * off echo, for runtime passphrase prompts.
1257 */
1258 int pipefd[2];
1259 if (pipe(pipefd) == 0) {
1260 pid_t pid = fork();
1261 if (pid == 0) {
1262 tcsetattr(upc->passphrase_fd, TCSADRAIN, &new_termios);
1263 close(pipefd[1]);
1264 char buf[4096];
1265 while (read(pipefd[0], buf, sizeof(buf)) > 0);
1266 tcsetattr(upc->passphrase_fd, TCSADRAIN, &new_termios);
1267 _exit(0);
1268 } else if (pid > 0) {
1269 upc->prompt_type = RTPROMPT_DEBUG;
1270 }
1271
1272 close(pipefd[0]);
1273 if (pid < 0)
1274 close(pipefd[1]);
1275 }
1276 }
1277 } else if (life == LIFE_EXEC) {
1278 pid_t agentpid, pid;
1279
1280 agentpid = getpid();
1281 setup_sigchld_handler();
1282
1283 pid = fork();
1284 if (pid < 0) {
1285 perror("fork");
1286 exit(1);
1287 } else if (pid == 0) {
1288 setenv("SSH_AUTH_SOCK", socketname, true);
1289 setenv("SSH_AGENT_PID", dupprintf("%d", (int)agentpid), true);
1290 execvp(exec_args[0], exec_args);
1291 perror("exec");
1292 _exit(127);
1293 } else {
1294 upc->termination_pid = pid;
1295 }
1296 }
1297
1298 if (!upc->logfp)
1299 upc->plc.suppress_logging = true;
1300
1301 cli_main_loop(agent_loop_pw_setup, agent_loop_pw_check,
1302 agent_loop_continue, upc);
1303
1304 /*
1305 * Before terminating, clean up our Unix socket file if possible.
1306 */
1307 if (unlink(socketname) < 0) {
1308 fprintf(stderr, "pageant: %s: %s\n", socketname, strerror(errno));
1309 exit(1);
1310 }
1311
1312 strbuf_free(upc->prompt_buf);
1313 conf_free(conf);
1314 }
1315
main(int argc,char ** argv)1316 int main(int argc, char **argv)
1317 {
1318 bool doing_opts = true;
1319 keyact curr_keyact = KEYACT_AGENT_LOAD;
1320 const char *standalone_askpass_prompt = NULL;
1321 const char *symlink_path = NULL;
1322 FILE *logfp = NULL;
1323
1324 progname = argv[0];
1325
1326 /*
1327 * Process the command line.
1328 */
1329 while (--argc > 0) {
1330 char *p = *++argv;
1331 if (*p == '-' && doing_opts) {
1332 if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
1333 version();
1334 } else if (!strcmp(p, "--help")) {
1335 usage();
1336 exit(0);
1337 } else if (!strcmp(p, "-v")) {
1338 logfp = stderr;
1339 } else if (!strcmp(p, "-a")) {
1340 curr_keyact = KEYACT_CLIENT_ADD;
1341 } else if (!strcmp(p, "-d")) {
1342 curr_keyact = KEYACT_CLIENT_DEL;
1343 } else if (!strcmp(p, "-r")) {
1344 curr_keyact = KEYACT_CLIENT_REENCRYPT;
1345 } else if (!strcmp(p, "-s")) {
1346 shell_type = SHELL_SH;
1347 } else if (!strcmp(p, "-c")) {
1348 shell_type = SHELL_CSH;
1349 } else if (!strcmp(p, "-D")) {
1350 add_keyact(KEYACT_CLIENT_DEL_ALL, NULL);
1351 } else if (!strcmp(p, "-R")) {
1352 add_keyact(KEYACT_CLIENT_REENCRYPT_ALL, NULL);
1353 } else if (!strcmp(p, "-l")) {
1354 add_keyact(KEYACT_CLIENT_LIST, NULL);
1355 } else if (!strcmp(p, "--public")) {
1356 curr_keyact = KEYACT_CLIENT_PUBLIC;
1357 } else if (!strcmp(p, "--public-openssh") || !strcmp(p, "-L")) {
1358 curr_keyact = KEYACT_CLIENT_PUBLIC_OPENSSH;
1359 } else if (!strcmp(p, "-X")) {
1360 life = LIFE_X11;
1361 } else if (!strcmp(p, "-T")) {
1362 life = LIFE_TTY;
1363 } else if (!strcmp(p, "--no-decrypt") ||
1364 !strcmp(p, "-no-decrypt") ||
1365 !strcmp(p, "--no_decrypt") ||
1366 !strcmp(p, "-no_decrypt") ||
1367 !strcmp(p, "--nodecrypt") ||
1368 !strcmp(p, "-nodecrypt") ||
1369 !strcmp(p, "--encrypted") ||
1370 !strcmp(p, "-encrypted")) {
1371 if (curr_keyact == KEYACT_AGENT_LOAD)
1372 curr_keyact = KEYACT_AGENT_LOAD_ENCRYPTED;
1373 else if (curr_keyact == KEYACT_CLIENT_ADD)
1374 curr_keyact = KEYACT_CLIENT_ADD_ENCRYPTED;
1375 else {
1376 fprintf(stderr, "pageant: unexpected -E while not adding "
1377 "keys\n");
1378 exit(1);
1379 }
1380 } else if (!strcmp(p, "--debug")) {
1381 life = LIFE_DEBUG;
1382 } else if (!strcmp(p, "--test-sign")) {
1383 curr_keyact = KEYACT_CLIENT_SIGN;
1384 sign_flags = 0;
1385 } else if (strstartswith(p, "--test-sign-with-flags=")) {
1386 curr_keyact = KEYACT_CLIENT_SIGN;
1387 sign_flags = atoi(p + strlen("--test-sign-with-flags="));
1388 } else if (!strcmp(p, "--permanent")) {
1389 life = LIFE_PERM;
1390 } else if (!strcmp(p, "--exec")) {
1391 life = LIFE_EXEC;
1392 /* Now all subsequent arguments go to the exec command. */
1393 if (--argc > 0) {
1394 exec_args = ++argv;
1395 argc = 0; /* force end of option processing */
1396 } else {
1397 fprintf(stderr, "pageant: expected a command "
1398 "after --exec\n");
1399 exit(1);
1400 }
1401 } else if (!strcmp(p, "--tty-prompt")) {
1402 prompt_type = PROMPT_TTY;
1403 } else if (!strcmp(p, "--gui-prompt")) {
1404 prompt_type = PROMPT_GUI;
1405 } else if (!strcmp(p, "--askpass")) {
1406 if (--argc > 0) {
1407 standalone_askpass_prompt = *++argv;
1408 } else {
1409 fprintf(stderr, "pageant: expected a prompt message "
1410 "after --askpass\n");
1411 exit(1);
1412 }
1413 } else if (!strcmp(p, "--symlink")) {
1414 if (--argc > 0) {
1415 symlink_path = *++argv;
1416 } else {
1417 fprintf(stderr, "pageant: expected a pathname "
1418 "after --symlink\n");
1419 exit(1);
1420 }
1421 } else if (!strcmp(p, "-E") || !strcmp(p, "--fptype")) {
1422 const char *keyword;
1423 if (--argc > 0) {
1424 keyword = *++argv;
1425 } else {
1426 fprintf(stderr, "pageant: expected a type string "
1427 "after %s\n", p);
1428 exit(1);
1429 }
1430 if (!strcmp(keyword, "md5"))
1431 key_list_fptype = SSH_FPTYPE_MD5;
1432 else if (!strcmp(keyword, "sha256"))
1433 key_list_fptype = SSH_FPTYPE_SHA256;
1434 else {
1435 fprintf(stderr, "pageant: unknown fingerprint type `%s'\n",
1436 keyword);
1437 exit(1);
1438 }
1439 } else if (!strcmp(p, "--")) {
1440 doing_opts = false;
1441 } else {
1442 fprintf(stderr, "pageant: unrecognised option '%s'\n", p);
1443 exit(1);
1444 }
1445 } else {
1446 /*
1447 * Non-option arguments (apart from those after --exec,
1448 * which are treated specially above) are interpreted as
1449 * the names of private key files to either add or delete
1450 * from an agent.
1451 */
1452 add_keyact(curr_keyact, p);
1453 }
1454 }
1455
1456 if (life == LIFE_EXEC && !exec_args) {
1457 fprintf(stderr, "pageant: expected a command with --exec\n");
1458 exit(1);
1459 }
1460
1461 if (!display) {
1462 display = getenv("DISPLAY");
1463 if (display && !*display)
1464 display = NULL;
1465 }
1466
1467 /*
1468 * Deal with standalone-askpass mode.
1469 */
1470 if (standalone_askpass_prompt) {
1471 char *passphrase = askpass(standalone_askpass_prompt);
1472
1473 if (!passphrase)
1474 return 1;
1475
1476 puts(passphrase);
1477 fflush(stdout);
1478
1479 smemclr(passphrase, strlen(passphrase));
1480 sfree(passphrase);
1481 return 0;
1482 }
1483
1484 /*
1485 * Block SIGPIPE, so that we'll get EPIPE individually on
1486 * particular network connections that go wrong.
1487 */
1488 putty_signal(SIGPIPE, SIG_IGN);
1489
1490 sk_init();
1491 uxsel_init();
1492
1493 /*
1494 * Now distinguish our two main running modes. Either we're
1495 * actually starting up an agent, in which case we should have a
1496 * lifetime mode, and no key actions of KEYACT_CLIENT_* type; or
1497 * else we're contacting an existing agent to add or remove keys,
1498 * in which case we should have no lifetime mode, and no key
1499 * actions of KEYACT_AGENT_* type.
1500 */
1501 {
1502 bool has_agent_actions = false;
1503 bool has_client_actions = false;
1504 bool has_lifetime = false;
1505 const struct cmdline_key_action *act;
1506
1507 for (act = keyact_head; act; act = act->next) {
1508 if (is_agent_action(act->action))
1509 has_agent_actions = true;
1510 else
1511 has_client_actions = true;
1512 }
1513 if (life != LIFE_UNSPEC)
1514 has_lifetime = true;
1515
1516 if (has_lifetime && has_client_actions) {
1517 fprintf(stderr, "pageant: client key actions (-a, -d, -D, -r, -R, "
1518 "-l, -L) do not go with an agent lifetime option\n");
1519 exit(1);
1520 }
1521 if (!has_lifetime && has_agent_actions) {
1522 fprintf(stderr, "pageant: expected an agent lifetime option with"
1523 " bare key file arguments\n");
1524 exit(1);
1525 }
1526 if (!has_lifetime && !has_client_actions) {
1527 fprintf(stderr, "pageant: expected an agent lifetime option"
1528 " or a client key action\n");
1529 exit(1);
1530 }
1531
1532 if (has_lifetime) {
1533 run_agent(logfp, symlink_path);
1534 } else if (has_client_actions) {
1535 run_client();
1536 }
1537 }
1538
1539 return 0;
1540 }
1541