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