uppity.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. /*
  2. * SSH server for Unix: main program.
  3. *
  4. * ======================================================================
  5. *
  6. * This server is NOT SECURE!
  7. *
  8. * DO NOT DEPLOY IT IN A HOSTILE-FACING ENVIRONMENT!
  9. *
  10. * Its purpose is to speak the server end of everything PuTTY speaks
  11. * on the client side, so that I can test that I haven't broken PuTTY
  12. * when I reorganise its code, even things like RSA key exchange or
  13. * chained auth methods which it's hard to find a server that speaks
  14. * at all.
  15. *
  16. * It has no interaction with the OS's authentication system: the
  17. * authentications it will accept are configurable by command-line
  18. * option, and once you authenticate, it will run the connection
  19. * protocol - including all subprocesses and shells - under the same
  20. * Unix user id you started it under.
  21. *
  22. * It really is only suitable for testing the actual SSH protocol.
  23. * Don't use it for anything more serious!
  24. *
  25. * ======================================================================
  26. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <errno.h>
  30. #include <assert.h>
  31. #include <stdarg.h>
  32. #include <signal.h>
  33. #include <unistd.h>
  34. #include <fcntl.h>
  35. #include <termios.h>
  36. #include <pwd.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/time.h>
  39. #include "putty.h"
  40. #include "mpint.h"
  41. #include "ssh.h"
  42. #include "ssh/server.h"
  43. void modalfatalbox(const char *p, ...)
  44. {
  45. va_list ap;
  46. fprintf(stderr, "FATAL ERROR: ");
  47. va_start(ap, p);
  48. vfprintf(stderr, p, ap);
  49. va_end(ap);
  50. fputc('\n', stderr);
  51. exit(1);
  52. }
  53. void nonfatal(const char *p, ...)
  54. {
  55. va_list ap;
  56. fprintf(stderr, "ERROR: ");
  57. va_start(ap, p);
  58. vfprintf(stderr, p, ap);
  59. va_end(ap);
  60. fputc('\n', stderr);
  61. }
  62. char *platform_default_s(const char *name)
  63. {
  64. return NULL;
  65. }
  66. bool platform_default_b(const char *name, bool def)
  67. {
  68. return def;
  69. }
  70. int platform_default_i(const char *name, int def)
  71. {
  72. return def;
  73. }
  74. FontSpec *platform_default_fontspec(const char *name)
  75. {
  76. return fontspec_new_default();
  77. }
  78. Filename *platform_default_filename(const char *name)
  79. {
  80. return filename_from_str("");
  81. }
  82. char *x_get_default(const char *key)
  83. {
  84. return NULL; /* this is a stub */
  85. }
  86. void old_keyfile_warning(void) { }
  87. void timer_change_notify(unsigned long next)
  88. {
  89. }
  90. char *platform_get_x_display(void) { return NULL; }
  91. void make_unix_sftp_filehandle_key(void *data, size_t size)
  92. {
  93. random_read(data, size);
  94. }
  95. static bool verbose;
  96. struct server_config;
  97. struct AuthPolicyShared {
  98. struct AuthPolicy_ssh1_pubkey *ssh1keys;
  99. struct AuthPolicy_ssh2_pubkey *ssh2keys;
  100. };
  101. struct AuthPolicy {
  102. struct AuthPolicyShared *shared;
  103. int kbdint_state;
  104. };
  105. struct server_instance {
  106. unsigned id;
  107. AuthPolicy ap;
  108. LogPolicy logpolicy;
  109. struct server_config *cfg;
  110. };
  111. struct server_config {
  112. unsigned config_id;
  113. Conf *conf;
  114. const SshServerConfig *ssc;
  115. ssh_key **hostkeys;
  116. int nhostkeys;
  117. RSAKey *hostkey1;
  118. unsigned auth_methods;
  119. struct AuthPolicyShared *ap_shared;
  120. Socket *listening_socket;
  121. Plug listening_plug;
  122. };
  123. static unsigned next_id = 0;
  124. static void log_to_stderr(unsigned id, const char *msg)
  125. {
  126. if (id != (unsigned)-1)
  127. fprintf(stderr, "conn#%u: ", id);
  128. fputs(msg, stderr);
  129. fputc('\n', stderr);
  130. fflush(stderr);
  131. }
  132. static void server_eventlog(LogPolicy *lp, const char *event)
  133. {
  134. struct server_instance *inst = container_of(
  135. lp, struct server_instance, logpolicy);
  136. if (verbose)
  137. log_to_stderr(inst->id, event);
  138. }
  139. static void server_logging_error(LogPolicy *lp, const char *event)
  140. {
  141. struct server_instance *inst = container_of(
  142. lp, struct server_instance, logpolicy);
  143. log_to_stderr(inst->id, event); /* unconditional */
  144. }
  145. static int server_askappend(
  146. LogPolicy *lp, Filename *filename,
  147. void (*callback)(void *ctx, int result), void *ctx)
  148. {
  149. return 2; /* always overwrite (FIXME: could make this a cmdline option) */
  150. }
  151. static const LogPolicyVtable server_logpolicy_vt = {
  152. .eventlog = server_eventlog,
  153. .askappend = server_askappend,
  154. .logging_error = server_logging_error,
  155. .verbose = null_lp_verbose_no,
  156. };
  157. struct AuthPolicy_ssh1_pubkey {
  158. RSAKey key;
  159. struct AuthPolicy_ssh1_pubkey *next;
  160. };
  161. struct AuthPolicy_ssh2_pubkey {
  162. ptrlen public_blob;
  163. struct AuthPolicy_ssh2_pubkey *next;
  164. };
  165. unsigned auth_methods(AuthPolicy *ap)
  166. {
  167. struct server_instance *inst = container_of(
  168. ap, struct server_instance, ap);
  169. return inst->cfg->auth_methods;
  170. }
  171. bool auth_none(AuthPolicy *ap, ptrlen username)
  172. {
  173. struct server_instance *inst = container_of(
  174. ap, struct server_instance, ap);
  175. if (inst->cfg->auth_methods & AUTHMETHOD_NONE)
  176. return true;
  177. return false;
  178. }
  179. int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password,
  180. ptrlen *new_password_opt)
  181. {
  182. const char *PHONY_GOOD_PASSWORD = "weasel";
  183. const char *PHONY_BAD_PASSWORD = "ferret";
  184. if (!new_password_opt) {
  185. /* Accept login with our preconfigured good password */
  186. if (ptrlen_eq_string(password, PHONY_GOOD_PASSWORD))
  187. return 1;
  188. /* Don't outright reject the bad password, but insist on a change */
  189. if (ptrlen_eq_string(password, PHONY_BAD_PASSWORD))
  190. return 2;
  191. /* Reject anything else */
  192. return 0;
  193. } else {
  194. /* In a password-change request, expect the bad password as input */
  195. if (!ptrlen_eq_string(password, PHONY_BAD_PASSWORD))
  196. return 0;
  197. /* Accept a request to change it to the good password */
  198. if (ptrlen_eq_string(*new_password_opt, PHONY_GOOD_PASSWORD))
  199. return 1;
  200. /* Outright reject a request to change it to the same password
  201. * as it already 'was' */
  202. if (ptrlen_eq_string(*new_password_opt, PHONY_BAD_PASSWORD))
  203. return 0;
  204. /* Anything else, pretend the new pw wasn't good enough, and
  205. * re-request a change */
  206. return 2;
  207. }
  208. }
  209. bool auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob)
  210. {
  211. struct AuthPolicy_ssh2_pubkey *iter;
  212. for (iter = ap->shared->ssh2keys; iter; iter = iter->next) {
  213. if (ptrlen_eq_ptrlen(public_blob, iter->public_blob))
  214. return true;
  215. }
  216. return false;
  217. }
  218. RSAKey *auth_publickey_ssh1(
  219. AuthPolicy *ap, ptrlen username, mp_int *rsa_modulus)
  220. {
  221. struct AuthPolicy_ssh1_pubkey *iter;
  222. for (iter = ap->shared->ssh1keys; iter; iter = iter->next) {
  223. if (mp_cmp_eq(rsa_modulus, iter->key.modulus))
  224. return &iter->key;
  225. }
  226. return NULL;
  227. }
  228. AuthKbdInt *auth_kbdint_prompts(AuthPolicy *ap, ptrlen username)
  229. {
  230. AuthKbdInt *aki;
  231. switch (ap->kbdint_state) {
  232. case 0:
  233. aki = snew(AuthKbdInt);
  234. aki->title = dupstr("Initial double prompt");
  235. aki->instruction =
  236. dupstr("First prompt should echo, second should not");
  237. aki->nprompts = 2;
  238. aki->prompts = snewn(aki->nprompts, AuthKbdIntPrompt);
  239. aki->prompts[0].prompt = dupstr("Echoey prompt: ");
  240. aki->prompts[0].echo = true;
  241. aki->prompts[1].prompt = dupstr("Silent prompt: ");
  242. aki->prompts[1].echo = false;
  243. return aki;
  244. case 1: {
  245. struct server_instance *inst = container_of(
  246. ap, struct server_instance, ap);
  247. aki = snew(AuthKbdInt);
  248. if (inst->cfg->ssc->stunt_allow_trivial_ki_auth) {
  249. aki->title = dupstr("");
  250. aki->instruction = dupstr("");
  251. } else {
  252. aki->title = dupstr("Zero-prompt step");
  253. aki->instruction = dupstr("Shouldn't see any prompts this time");
  254. }
  255. aki->nprompts = 0;
  256. aki->prompts = NULL;
  257. return aki;
  258. }
  259. default:
  260. ap->kbdint_state = 0;
  261. return NULL;
  262. }
  263. }
  264. int auth_kbdint_responses(AuthPolicy *ap, const ptrlen *responses)
  265. {
  266. switch (ap->kbdint_state) {
  267. case 0:
  268. if (ptrlen_eq_string(responses[0], "stoat") &&
  269. ptrlen_eq_string(responses[1], "weasel")) {
  270. ap->kbdint_state++;
  271. return 0; /* those are the expected responses */
  272. } else {
  273. ap->kbdint_state = 0;
  274. return -1;
  275. }
  276. break;
  277. case 1:
  278. return +1; /* succeed after the zero-prompt step */
  279. default:
  280. ap->kbdint_state = 0;
  281. return -1;
  282. }
  283. }
  284. char *auth_ssh1int_challenge(AuthPolicy *ap, unsigned method, ptrlen username)
  285. {
  286. /* FIXME: test returning a challenge string without \n, and ensure
  287. * it gets printed as a prompt in its own right, without PuTTY
  288. * making up a "Response: " prompt to follow it */
  289. return dupprintf("This is a dummy %s challenge!\n",
  290. (method == AUTHMETHOD_TIS ? "TIS" : "CryptoCard"));
  291. }
  292. bool auth_ssh1int_response(AuthPolicy *ap, ptrlen response)
  293. {
  294. return ptrlen_eq_string(response, "otter");
  295. }
  296. bool auth_successful(AuthPolicy *ap, ptrlen username, unsigned method)
  297. {
  298. return true;
  299. }
  300. static void safety_warning(FILE *fp)
  301. {
  302. fputs(" =================================================\n"
  303. " THIS SSH SERVER IS NOT WRITTEN TO BE SECURE!\n"
  304. " DO NOT DEPLOY IT IN A HOSTILE-FACING ENVIRONMENT!\n"
  305. " =================================================\n", fp);
  306. }
  307. static void show_help(FILE *fp)
  308. {
  309. safety_warning(fp);
  310. fputs("\n"
  311. "usage: uppity [options] [--and <options>...]\n"
  312. "options: --listen [PORT|PATH] listen to a port on localhost, or Unix socket\n"
  313. " --listen-once (with --listen) stop after one "
  314. "connection\n"
  315. " --hostkey KEY SSH host key (need at least one)\n"
  316. " --rsakexkey KEY key for SSH-2 RSA key exchange "
  317. "(in SSH-1 format)\n"
  318. " --userkey KEY public key"
  319. " acceptable for user authentication\n"
  320. " --sessiondir DIR cwd for session subprocess (default $HOME)\n"
  321. " --bannertext TEXT send TEXT as SSH-2 auth banner\n"
  322. " --bannerfile FILE send contents of FILE as SSH-2 auth "
  323. "banner\n"
  324. " --kexinit-kex STR override list of SSH-2 KEX methods\n"
  325. " --kexinit-hostkey STR override list of SSH-2 host key "
  326. "types\n"
  327. " --kexinit-cscipher STR override list of SSH-2 "
  328. "client->server ciphers\n"
  329. " --kexinit-sccipher STR override list of SSH-2 "
  330. "server->client ciphers\n"
  331. " --kexinit-csmac STR override list of SSH-2 "
  332. "client->server MACs\n"
  333. " --kexinit-scmac STR override list of SSH-2 "
  334. "server->client MACs\n"
  335. " --kexinit-cscomp STR override list of SSH-2 "
  336. "c->s compression types\n"
  337. " --kexinit-sccomp STR override list of SSH-2 "
  338. "s->c compression types\n"
  339. " --ssh1-ciphers STR override list of SSH-1 ciphers\n"
  340. " --ssh1-no-compression forbid compression in SSH-1\n"
  341. " --deny-auth METHOD forbid a userauth method\n"
  342. " --allow-auth METHOD allow a userauth method\n"
  343. " (METHOD = none/password/publickey/kbdint/tis/"
  344. "cryptocard)\n"
  345. " --exitsignum send buggy numeric \"exit-signal\" "
  346. "message\n"
  347. " --verbose print event log messages to standard "
  348. "error\n"
  349. " --sshlog FILE write SSH packet log to FILE\n"
  350. " --sshrawlog FILE write SSH packets + raw data log"
  351. " to FILE\n"
  352. " --and run a separate server on another port\n"
  353. "also: uppity --help show this text\n"
  354. " uppity --version show version information\n"
  355. "\n", fp);
  356. safety_warning(fp);
  357. }
  358. static void show_version_and_exit(void)
  359. {
  360. char *buildinfo_text = buildinfo("\n");
  361. printf("%s: %s\n%s\n", appname, ver, buildinfo_text);
  362. sfree(buildinfo_text);
  363. exit(0);
  364. }
  365. const bool buildinfo_gtk_relevant = false;
  366. static bool listening = false, listen_once = false;
  367. static bool finished = false;
  368. void server_instance_terminated(LogPolicy *lp)
  369. {
  370. struct server_instance *inst = container_of(
  371. lp, struct server_instance, logpolicy);
  372. if (listening && !listen_once) {
  373. log_to_stderr(inst->id, "connection terminated");
  374. } else {
  375. finished = true;
  376. }
  377. sfree(inst);
  378. }
  379. static bool longoptarg(const char *arg, const char *expected,
  380. const char **val, int *argcp, char ***argvp)
  381. {
  382. int len = strlen(expected);
  383. if (memcmp(arg, expected, len))
  384. return false;
  385. if (arg[len] == '=') {
  386. *val = arg + len + 1;
  387. return true;
  388. } else if (arg[len] == '\0') {
  389. if (--*argcp > 0) {
  390. *val = *++*argvp;
  391. return true;
  392. } else {
  393. fprintf(stderr, "%s: option %s expects an argument\n",
  394. appname, expected);
  395. exit(1);
  396. }
  397. }
  398. return false;
  399. }
  400. static bool longoptnoarg(const char *arg, const char *expected)
  401. {
  402. int len = strlen(expected);
  403. if (memcmp(arg, expected, len))
  404. return false;
  405. if (arg[len] == '=') {
  406. fprintf(stderr, "%s: option %s expects no argument\n",
  407. appname, expected);
  408. exit(1);
  409. } else if (arg[len] == '\0') {
  410. return true;
  411. }
  412. return false;
  413. }
  414. static Plug *server_conn_plug(
  415. struct server_config *cfg, struct server_instance **inst_out)
  416. {
  417. struct server_instance *inst = snew(struct server_instance);
  418. memset(inst, 0, sizeof(*inst));
  419. inst->id = next_id++;
  420. inst->ap.shared = cfg->ap_shared;
  421. if (cfg->ssc->stunt_allow_trivial_ki_auth)
  422. inst->ap.kbdint_state = 1;
  423. inst->logpolicy.vt = &server_logpolicy_vt;
  424. inst->cfg = cfg;
  425. if (inst_out)
  426. *inst_out = inst;
  427. return ssh_server_plug(
  428. cfg->conf, cfg->ssc, cfg->hostkeys, cfg->nhostkeys, cfg->hostkey1,
  429. &inst->ap, &inst->logpolicy, &unix_live_sftpserver_vt);
  430. }
  431. static void server_log(Plug *plug, Socket *s, PlugLogType type, SockAddr *addr,
  432. int port, const char *error_msg, int error_code)
  433. {
  434. log_to_stderr((unsigned)-1, error_msg);
  435. }
  436. static void server_closing(Plug *plug, PlugCloseType type,
  437. const char *error_msg)
  438. {
  439. if (type != PLUGCLOSE_NORMAL)
  440. log_to_stderr((unsigned)-1, error_msg);
  441. }
  442. static int server_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
  443. {
  444. struct server_config *cfg = container_of(
  445. p, struct server_config, listening_plug);
  446. Socket *s;
  447. const char *err;
  448. struct server_instance *inst;
  449. if (listen_once) {
  450. if (!cfg->listening_socket) /* in case of rapid double-accept */
  451. return 1;
  452. sk_close(cfg->listening_socket);
  453. cfg->listening_socket = NULL;
  454. }
  455. unsigned old_next_id = next_id;
  456. Plug *plug = server_conn_plug(cfg, &inst);
  457. s = constructor(ctx, plug);
  458. if ((err = sk_socket_error(s)) != NULL)
  459. return 1;
  460. SocketEndpointInfo *pi = sk_peer_info(s);
  461. if (pi->addressfamily != ADDRTYPE_LOCAL && !sk_peer_trusted(s)) {
  462. fprintf(stderr, "rejected connection to serv#%u "
  463. "from %s (untrustworthy peer)\n",
  464. cfg->config_id, pi->log_text);
  465. sk_free_endpoint_info(pi);
  466. sk_close(s);
  467. next_id = old_next_id;
  468. return 1;
  469. }
  470. char *msg = dupprintf("new connection to serv#%u from %s",
  471. cfg->config_id, pi->log_text);
  472. log_to_stderr(inst->id, msg);
  473. sfree(msg);
  474. sk_free_endpoint_info(pi);
  475. sk_set_frozen(s, false);
  476. ssh_server_start(plug, s);
  477. return 0;
  478. }
  479. static const PlugVtable server_plugvt = {
  480. .log = server_log,
  481. .closing = server_closing,
  482. .accepting = server_accepting,
  483. };
  484. static unsigned auth_method_from_name(const char *name)
  485. {
  486. if (!strcmp(name, "none"))
  487. return AUTHMETHOD_NONE;
  488. if (!strcmp(name, "tis"))
  489. return AUTHMETHOD_TIS;
  490. if (!strcmp(name, "cryptocard") || !strcmp(name, "ccard"))
  491. return AUTHMETHOD_CRYPTOCARD;
  492. if (!strcmp(name, "keyboard-interactive") || !strcmp(name, "k-i") ||
  493. !strcmp(name, "kbdint") || !strcmp(name, "ki"))
  494. return AUTHMETHOD_KBDINT;
  495. if (!strcmp(name, "publickey") || !strcmp(name, "pubkey") ||
  496. !strcmp(name, "pk"))
  497. return AUTHMETHOD_PUBLICKEY;
  498. if (!strcmp(name, "password") || !strcmp(name, "pw"))
  499. return AUTHMETHOD_PASSWORD;
  500. return 0;
  501. }
  502. struct cmdline_instance {
  503. int listen_port;
  504. const char *listen_socket;
  505. ssh_key **hostkeys;
  506. size_t nhostkeys, hostkeysize;
  507. RSAKey *hostkey1;
  508. unsigned auth_methods;
  509. struct AuthPolicyShared aps;
  510. SshServerConfig ssc;
  511. Conf *conf;
  512. };
  513. static void init_cmdline_instance(struct cmdline_instance *ci)
  514. {
  515. ci->listen_port = -1;
  516. ci->listen_socket = NULL;
  517. ci->hostkeys = NULL;
  518. ci->nhostkeys = ci->hostkeysize = 0;
  519. ci->hostkey1 = NULL;
  520. ci->conf = make_ssh_server_conf();
  521. ci->aps.ssh1keys = NULL;
  522. ci->aps.ssh2keys = NULL;
  523. memset(&ci->ssc, 0, sizeof(ci->ssc));
  524. ci->ssc.application_name = "Uppity";
  525. ci->ssc.session_starting_dir = getenv("HOME");
  526. ci->ssc.ssh1_cipher_mask = SSH1_SUPPORTED_CIPHER_MASK;
  527. ci->ssc.ssh1_allow_compression = true;
  528. ci->auth_methods = (AUTHMETHOD_PUBLICKEY | AUTHMETHOD_PASSWORD |
  529. AUTHMETHOD_KBDINT | AUTHMETHOD_TIS |
  530. AUTHMETHOD_CRYPTOCARD);
  531. }
  532. static void cmdline_instance_start(struct cmdline_instance *ci)
  533. {
  534. static unsigned next_server_config_id = 0;
  535. struct server_config *scfg = snew(struct server_config);
  536. scfg->config_id = next_server_config_id++;
  537. scfg->conf = ci->conf;
  538. scfg->ssc = &ci->ssc;
  539. scfg->hostkeys = ci->hostkeys;
  540. scfg->nhostkeys = ci->nhostkeys;
  541. scfg->hostkey1 = ci->hostkey1;
  542. scfg->ap_shared = &ci->aps;
  543. scfg->auth_methods = ci->auth_methods;
  544. if (ci->listen_port >= 0 || ci->listen_socket) {
  545. listening = true;
  546. scfg->listening_plug.vt = &server_plugvt;
  547. char *msg;
  548. if (ci->listen_port >= 0) {
  549. scfg->listening_socket = sk_newlistener(
  550. NULL, ci->listen_port, &scfg->listening_plug, true,
  551. ADDRTYPE_UNSPEC);
  552. msg = dupprintf("serv#%u: listening on port %d",
  553. scfg->config_id, ci->listen_port);
  554. } else {
  555. SockAddr *addr = unix_sock_addr(ci->listen_socket);
  556. scfg->listening_socket = new_unix_listener(
  557. addr, &scfg->listening_plug);
  558. msg = dupprintf("serv#%u: listening on Unix socket %s",
  559. scfg->config_id, ci->listen_socket);
  560. }
  561. log_to_stderr(-1, msg);
  562. sfree(msg);
  563. } else {
  564. struct server_instance *inst;
  565. Plug *plug = server_conn_plug(scfg, &inst);
  566. ssh_server_start(plug, make_fd_socket(0, 1, -1, NULL, 0, plug));
  567. log_to_stderr(inst->id, "speaking SSH on stdio");
  568. }
  569. }
  570. int main(int argc, char **argv)
  571. {
  572. size_t ninstances = 0, instancessize = 8;
  573. struct cmdline_instance *instances = snewn(
  574. instancessize, struct cmdline_instance);
  575. struct cmdline_instance *ci = &instances[ninstances++];
  576. init_cmdline_instance(ci);
  577. enable_dit();
  578. if (argc <= 1) {
  579. /*
  580. * We're going to terminate with an error message below,
  581. * because there are no host keys. But we'll display the help
  582. * as additional standard-error output, if nothing else so
  583. * that people see the giant safety warning.
  584. */
  585. show_help(stderr);
  586. fputc('\n', stderr);
  587. }
  588. while (--argc > 0) {
  589. const char *arg = *++argv;
  590. const char *val;
  591. if (!strcmp(arg, "--help")) {
  592. show_help(stdout);
  593. exit(0);
  594. } else if (longoptnoarg(arg, "--version")) {
  595. show_version_and_exit();
  596. } else if (longoptnoarg(arg, "--verbose") || !strcmp(arg, "-v")) {
  597. verbose = true;
  598. } else if (longoptnoarg(arg, "--and")) {
  599. sgrowarray(instances, instancessize, ninstances);
  600. ci = &instances[ninstances++];
  601. init_cmdline_instance(ci);
  602. } else if (longoptarg(arg, "--listen", &val, &argc, &argv)) {
  603. if (val[0] == '/') {
  604. ci->listen_port = -1;
  605. ci->listen_socket = val;
  606. } else {
  607. ci->listen_port = atoi(val);
  608. ci->listen_socket = NULL;
  609. }
  610. } else if (!strcmp(arg, "--listen-once")) {
  611. listen_once = true;
  612. } else if (longoptarg(arg, "--hostkey", &val, &argc, &argv)) {
  613. Filename *keyfile;
  614. int keytype;
  615. const char *error;
  616. keyfile = filename_from_str(val);
  617. keytype = key_type(keyfile);
  618. if (keytype == SSH_KEYTYPE_SSH2) {
  619. ssh2_userkey *uk;
  620. ssh_key *key;
  621. uk = ppk_load_f(keyfile, NULL, &error);
  622. filename_free(keyfile);
  623. if (!uk || !uk->key) {
  624. fprintf(stderr, "%s: unable to load host key '%s': "
  625. "%s\n", appname, val, error);
  626. exit(1);
  627. }
  628. char *invalid = ssh_key_invalid(uk->key, 0);
  629. if (invalid) {
  630. fprintf(stderr, "%s: host key '%s' is unusable: "
  631. "%s\n", appname, val, invalid);
  632. exit(1);
  633. }
  634. key = uk->key;
  635. sfree(uk->comment);
  636. sfree(uk);
  637. for (int i = 0; i < ci->nhostkeys; i++)
  638. if (ssh_key_alg(ci->hostkeys[i]) == ssh_key_alg(key)) {
  639. fprintf(stderr, "%s: host key '%s' duplicates key "
  640. "type %s\n", appname, val,
  641. ssh_key_alg(key)->ssh_id);
  642. exit(1);
  643. }
  644. sgrowarray(ci->hostkeys, ci->hostkeysize, ci->nhostkeys);
  645. ci->hostkeys[ci->nhostkeys++] = key;
  646. } else if (keytype == SSH_KEYTYPE_SSH1) {
  647. if (ci->hostkey1) {
  648. fprintf(stderr, "%s: host key '%s' is a redundant "
  649. "SSH-1 host key\n", appname, val);
  650. exit(1);
  651. }
  652. ci->hostkey1 = snew(RSAKey);
  653. if (!rsa1_load_f(keyfile, ci->hostkey1, NULL, &error)) {
  654. fprintf(stderr, "%s: unable to load host key '%s': "
  655. "%s\n", appname, val, error);
  656. exit(1);
  657. }
  658. } else {
  659. fprintf(stderr, "%s: '%s' is not loadable as a "
  660. "private key (%s)", appname, val,
  661. key_type_to_str(keytype));
  662. exit(1);
  663. }
  664. } else if (longoptarg(arg, "--rsakexkey", &val, &argc, &argv)) {
  665. Filename *keyfile;
  666. int keytype;
  667. const char *error;
  668. keyfile = filename_from_str(val);
  669. keytype = key_type(keyfile);
  670. if (keytype != SSH_KEYTYPE_SSH1) {
  671. fprintf(stderr, "%s: '%s' is not loadable as an SSH-1 format "
  672. "private key (%s)", appname, val,
  673. key_type_to_str(keytype));
  674. exit(1);
  675. }
  676. if (ci->ssc.rsa_kex_key) {
  677. freersakey(ci->ssc.rsa_kex_key);
  678. } else {
  679. ci->ssc.rsa_kex_key = snew(RSAKey);
  680. }
  681. if (!rsa1_load_f(keyfile, ci->ssc.rsa_kex_key, NULL, &error)) {
  682. fprintf(stderr, "%s: unable to load RSA kex key '%s': "
  683. "%s\n", appname, val, error);
  684. exit(1);
  685. }
  686. ci->ssc.rsa_kex_key->sshk.vt = &ssh_rsa;
  687. } else if (longoptarg(arg, "--userkey", &val, &argc, &argv)) {
  688. Filename *keyfile;
  689. int keytype;
  690. const char *error;
  691. keyfile = filename_from_str(val);
  692. keytype = key_type(keyfile);
  693. if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||
  694. keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
  695. strbuf *sb = strbuf_new();
  696. struct AuthPolicy_ssh2_pubkey *node;
  697. void *blob;
  698. if (!ppk_loadpub_f(keyfile, NULL, BinarySink_UPCAST(sb),
  699. NULL, &error)) {
  700. fprintf(stderr, "%s: unable to load user key '%s': "
  701. "%s\n", appname, val, error);
  702. exit(1);
  703. }
  704. node = snew_plus(struct AuthPolicy_ssh2_pubkey, sb->len);
  705. blob = snew_plus_get_aux(node);
  706. memcpy(blob, sb->u, sb->len);
  707. node->public_blob = make_ptrlen(blob, sb->len);
  708. node->next = ci->aps.ssh2keys;
  709. ci->aps.ssh2keys = node;
  710. strbuf_free(sb);
  711. } else if (keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
  712. strbuf *sb = strbuf_new();
  713. BinarySource src[1];
  714. struct AuthPolicy_ssh1_pubkey *node;
  715. if (!rsa1_loadpub_f(keyfile, BinarySink_UPCAST(sb),
  716. NULL, &error)) {
  717. fprintf(stderr, "%s: unable to load user key '%s': "
  718. "%s\n", appname, val, error);
  719. exit(1);
  720. }
  721. node = snew(struct AuthPolicy_ssh1_pubkey);
  722. BinarySource_BARE_INIT(src, sb->u, sb->len);
  723. get_rsa_ssh1_pub(src, &node->key, RSA_SSH1_EXPONENT_FIRST);
  724. node->next = ci->aps.ssh1keys;
  725. ci->aps.ssh1keys = node;
  726. strbuf_free(sb);
  727. } else {
  728. fprintf(stderr, "%s: '%s' is not loadable as a public key "
  729. "(%s)\n", appname, val, key_type_to_str(keytype));
  730. exit(1);
  731. }
  732. } else if (longoptarg(arg, "--bannerfile", &val, &argc, &argv)) {
  733. FILE *fp = fopen(val, "r");
  734. if (!fp) {
  735. fprintf(stderr, "%s: %s: open: %s\n", appname,
  736. val, strerror(errno));
  737. exit(1);
  738. }
  739. strbuf *sb = strbuf_new();
  740. if (!read_file_into(BinarySink_UPCAST(sb), fp)) {
  741. fprintf(stderr, "%s: %s: read: %s\n", appname,
  742. val, strerror(errno));
  743. exit(1);
  744. }
  745. fclose(fp);
  746. ci->ssc.banner = ptrlen_from_strbuf(sb);
  747. } else if (longoptarg(arg, "--bannertext", &val, &argc, &argv)) {
  748. ci->ssc.banner = ptrlen_from_asciz(val);
  749. } else if (longoptarg(arg, "--sessiondir", &val, &argc, &argv)) {
  750. ci->ssc.session_starting_dir = val;
  751. } else if (longoptarg(arg, "--kexinit-kex", &val, &argc, &argv)) {
  752. ci->ssc.kex_override[KEXLIST_KEX] = ptrlen_from_asciz(val);
  753. } else if (longoptarg(arg, "--kexinit-hostkey", &val, &argc, &argv)) {
  754. ci->ssc.kex_override[KEXLIST_HOSTKEY] = ptrlen_from_asciz(val);
  755. } else if (longoptarg(arg, "--kexinit-cscipher", &val, &argc, &argv)) {
  756. ci->ssc.kex_override[KEXLIST_CSCIPHER] = ptrlen_from_asciz(val);
  757. } else if (longoptarg(arg, "--kexinit-csmac", &val, &argc, &argv)) {
  758. ci->ssc.kex_override[KEXLIST_CSMAC] = ptrlen_from_asciz(val);
  759. } else if (longoptarg(arg, "--kexinit-cscomp", &val, &argc, &argv)) {
  760. ci->ssc.kex_override[KEXLIST_CSCOMP] = ptrlen_from_asciz(val);
  761. } else if (longoptarg(arg, "--kexinit-sccipher", &val, &argc, &argv)) {
  762. ci->ssc.kex_override[KEXLIST_SCCIPHER] = ptrlen_from_asciz(val);
  763. } else if (longoptarg(arg, "--kexinit-scmac", &val, &argc, &argv)) {
  764. ci->ssc.kex_override[KEXLIST_SCMAC] = ptrlen_from_asciz(val);
  765. } else if (longoptarg(arg, "--kexinit-sccomp", &val, &argc, &argv)) {
  766. ci->ssc.kex_override[KEXLIST_SCCOMP] = ptrlen_from_asciz(val);
  767. } else if (longoptarg(arg, "--allow-auth", &val, &argc, &argv)) {
  768. unsigned method = auth_method_from_name(val);
  769. if (!method) {
  770. fprintf(stderr, "%s: unrecognised auth method '%s'\n",
  771. appname, val);
  772. exit(1);
  773. }
  774. ci->auth_methods |= method;
  775. } else if (longoptarg(arg, "--deny-auth", &val, &argc, &argv)) {
  776. unsigned method = auth_method_from_name(val);
  777. if (!method) {
  778. fprintf(stderr, "%s: unrecognised auth method '%s'\n",
  779. appname, val);
  780. exit(1);
  781. }
  782. ci->auth_methods &= ~method;
  783. } else if (longoptarg(arg, "--ssh1-ciphers", &val, &argc, &argv)) {
  784. ptrlen list = ptrlen_from_asciz(val);
  785. ptrlen word;
  786. unsigned long mask = 0;
  787. while (word = ptrlen_get_word(&list, ","), word.len != 0) {
  788. #define SSH1_CIPHER_CASE(bitpos, name) \
  789. if (ptrlen_eq_string(word, name)) { \
  790. mask |= 1U << bitpos; \
  791. continue; \
  792. }
  793. SSH1_SUPPORTED_CIPHER_LIST(SSH1_CIPHER_CASE);
  794. #undef SSH1_CIPHER_CASE
  795. fprintf(stderr, "%s: unrecognised SSH-1 cipher '%.*s'\n",
  796. appname, PTRLEN_PRINTF(word));
  797. exit(1);
  798. }
  799. ci->ssc.ssh1_cipher_mask = mask;
  800. } else if (longoptnoarg(arg, "--ssh1-no-compression")) {
  801. ci->ssc.ssh1_allow_compression = false;
  802. } else if (longoptnoarg(arg, "--exitsignum")) {
  803. ci->ssc.exit_signal_numeric = true;
  804. } else if (longoptarg(arg, "--sshlog", &val, &argc, &argv) ||
  805. longoptarg(arg, "-sshlog", &val, &argc, &argv)) {
  806. Filename *logfile = filename_from_str(val);
  807. conf_set_filename(ci->conf, CONF_logfilename, logfile);
  808. filename_free(logfile);
  809. conf_set_int(ci->conf, CONF_logtype, LGTYP_PACKETS);
  810. conf_set_int(ci->conf, CONF_logxfovr, LGXF_OVR);
  811. } else if (longoptarg(arg, "--sshrawlog", &val, &argc, &argv) ||
  812. longoptarg(arg, "-sshrawlog", &val, &argc, &argv)) {
  813. Filename *logfile = filename_from_str(val);
  814. conf_set_filename(ci->conf, CONF_logfilename, logfile);
  815. filename_free(logfile);
  816. conf_set_int(ci->conf, CONF_logtype, LGTYP_SSHRAW);
  817. conf_set_int(ci->conf, CONF_logxfovr, LGXF_OVR);
  818. } else if (!strcmp(arg, "--pretend-to-accept-any-pubkey")) {
  819. ci->ssc.stunt_pretend_to_accept_any_pubkey = true;
  820. } else if (!strcmp(arg, "--open-unconditional-agent-socket")) {
  821. ci->ssc.stunt_open_unconditional_agent_socket = true;
  822. } else if (!strcmp(arg, "--allow-none-auth")) {
  823. /* backwards-compatibility synonym for --allow-auth=none */
  824. ci->auth_methods |= AUTHMETHOD_NONE;
  825. } else if (!strcmp(arg, "--allow-trivial-ki-auth")) {
  826. ci->ssc.stunt_allow_trivial_ki_auth = true;
  827. } else if (!strcmp(arg, "--return-success-to-pubkey-offer")) {
  828. ci->ssc.stunt_return_success_to_pubkey_offer = true;
  829. } else if (!strcmp(arg, "--close-after-banner")) {
  830. ci->ssc.stunt_close_after_banner = true;
  831. } else {
  832. fprintf(stderr, "%s: unrecognised option '%s'\n", appname, arg);
  833. exit(1);
  834. }
  835. }
  836. if (ninstances > 1 && listen_once) {
  837. fprintf(stderr, "%s: cannot listen once only with multiple server "
  838. "instances\n", appname);
  839. exit(1);
  840. }
  841. for (size_t i = 0; i < ninstances; i++) {
  842. ci = &instances[i];
  843. if (ci->nhostkeys == 0 && !ci->hostkey1) {
  844. fprintf(stderr, "%s: specify at least one host key\n", appname);
  845. exit(1);
  846. }
  847. if (ninstances > 1 && !(ci->listen_port >= 0 || ci->listen_socket)) {
  848. fprintf(stderr, "%s: cannot talk to stdio with multiple server "
  849. "instances\n", appname);
  850. exit(1);
  851. }
  852. }
  853. random_ref();
  854. /*
  855. * Block SIGPIPE, so that we'll get EPIPE individually on
  856. * particular network connections that go wrong.
  857. */
  858. putty_signal(SIGPIPE, SIG_IGN);
  859. sk_init();
  860. uxsel_init();
  861. for (size_t i = 0; i < ninstances; i++)
  862. cmdline_instance_start(&instances[i]);
  863. cli_main_loop(cliloop_no_pw_setup, cliloop_no_pw_check,
  864. cliloop_always_continue, NULL);
  865. return 0;
  866. }