pageant.c 48 KB

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