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