1 /* $OpenBSD: sshd-auth.c,v 1.2 2024/12/03 22:30:03 jsg Exp $ */
4 * Privilege Separation:
6 * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved.
7 * Copyright (c) 2002 Niels Provos. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
36 #include <sys/socket.h>
39 #include "openbsd-compat/sys-tree.h"
40 #include "openbsd-compat/sys-queue.h"
59 #include <openssl/bn.h>
60 #include <openssl/evp.h>
80 #include "pathnames.h"
94 #include "monitor_wrap.h"
95 #include "auth-options.h"
100 #include "ssh-sandbox.h"
104 #define PRIVSEP_MONITOR_FD (STDERR_FILENO + 1)
105 #define PRIVSEP_LOG_FD (STDERR_FILENO + 2)
106 #define PRIVSEP_MIN_FREE_FD (STDERR_FILENO + 3)
108 extern char *__progname
;
110 /* Server configuration options. */
111 ServerOptions options
;
113 /* Name of the server configuration file. */
114 char *config_file_name
= _PATH_SERVER_CONFIG_FILE
;
117 * Debug mode flag. This can be set on the command line. If debug
118 * mode is enabled, extra debugging output will be sent to the system
119 * log, the daemon will not go to background, and will exit after processing
120 * the first connection.
124 /* Flag indicating that the daemon is being started from inetd. */
125 static int inetd_flag
= 0;
127 /* Saved arguments to main(). */
128 static char **saved_argv
;
129 static int saved_argc
;
132 /* Daemon's agent connection */
134 static int have_agent
= 0;
137 struct sshkey
**host_pubkeys
; /* all public host keys */
138 struct sshkey
**host_certificates
; /* all public host certificates */
140 /* record remote hostname or ip */
141 u_int utmp_len
= HOST_NAME_MAX
+1;
143 /* variables used for privilege separation */
144 struct monitor
*pmonitor
= NULL
;
145 int privsep_is_preauth
= 1;
146 static int privsep_chroot
= 1;
148 /* global connection state and authentication contexts */
149 Authctxt
*the_authctxt
= NULL
;
150 struct ssh
*the_active_state
;
152 /* global key/cert auth options. XXX move to permanent ssh->authctxt? */
153 struct sshauthopt
*auth_opts
= NULL
;
155 /* sshd_config buffer */
158 /* Included files from the configuration file */
159 struct include_list includes
= TAILQ_HEAD_INITIALIZER(includes
);
161 /* message to be displayed after login */
162 struct sshbuf
*loginmsg
;
164 /* Prototypes for various functions defined later in this file. */
165 static void do_ssh2_kex(struct ssh
*);
167 /* Unprivileged user */
168 struct passwd
*privsep_pw
= NULL
;
171 static struct ssh_sandbox
*box
;
182 privsep_child_demote(void)
187 if ((box
= ssh_sandbox_init(pmonitor
)) == NULL
)
188 fatal_f("ssh_sandbox_init failed");
190 /* Demote the child */
191 if (privsep_chroot
) {
192 /* Change our root directory */
193 if (chroot(_PATH_PRIVSEP_CHROOT_DIR
) == -1)
194 fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR
,
196 if (chdir("/") == -1)
197 fatal("chdir(\"/\"): %s", strerror(errno
));
200 * Drop our privileges
201 * NB. Can't use setusercontext() after chroot.
203 debug3("privsep user:group %u:%u", (u_int
)privsep_pw
->pw_uid
,
204 (u_int
)privsep_pw
->pw_gid
);
205 gidset
[0] = privsep_pw
->pw_gid
;
206 if (setgroups(1, gidset
) == -1)
207 fatal("setgroups: %.100s", strerror(errno
));
208 permanently_set_uid(privsep_pw
);
211 /* sandbox ourselves */
213 if (pledge("stdio", NULL
) == -1)
216 ssh_sandbox_child(box
);
221 append_hostkey_type(struct sshbuf
*b
, const char *s
)
225 if (match_pattern_list(s
, options
.hostkeyalgorithms
, 0) != 1) {
226 debug3_f("%s key not permitted by HostkeyAlgorithms", s
);
229 if ((r
= sshbuf_putf(b
, "%s%s", sshbuf_len(b
) > 0 ? "," : "", s
)) != 0)
230 fatal_fr(r
, "sshbuf_putf");
234 list_hostkey_types(void)
241 if ((b
= sshbuf_new()) == NULL
)
242 fatal_f("sshbuf_new failed");
243 for (i
= 0; i
< options
.num_host_key_files
; i
++) {
244 key
= host_pubkeys
[i
];
249 /* for RSA we also support SHA2 signatures */
250 append_hostkey_type(b
, "rsa-sha2-512");
251 append_hostkey_type(b
, "rsa-sha2-256");
259 append_hostkey_type(b
, sshkey_ssh_name(key
));
262 /* If the private key has a cert peer, then list that too */
263 key
= host_certificates
[i
];
268 /* for RSA we also support SHA2 signatures */
269 append_hostkey_type(b
,
270 "rsa-sha2-512-cert-v01@openssh.com");
271 append_hostkey_type(b
,
272 "rsa-sha2-256-cert-v01@openssh.com");
276 case KEY_ED25519_CERT
:
277 case KEY_ECDSA_SK_CERT
:
278 case KEY_ED25519_SK_CERT
:
280 append_hostkey_type(b
, sshkey_ssh_name(key
));
284 if ((ret
= sshbuf_dup_string(b
)) == NULL
)
285 fatal_f("sshbuf_dup_string failed");
292 get_hostkey_public_by_type(int type
, int nid
, struct ssh
*ssh
)
297 for (i
= 0; i
< options
.num_host_key_files
; i
++) {
302 case KEY_ED25519_CERT
:
303 case KEY_ECDSA_SK_CERT
:
304 case KEY_ED25519_SK_CERT
:
306 key
= host_certificates
[i
];
309 key
= host_pubkeys
[i
];
312 if (key
== NULL
|| key
->type
!= type
)
318 case KEY_ECDSA_SK_CERT
:
319 if (key
->ecdsa_nid
!= nid
)
331 get_hostkey_private_by_type(int type
, int nid
, struct ssh
*ssh
)
338 get_hostkey_by_index(int ind
)
344 get_hostkey_public_by_index(int ind
, struct ssh
*ssh
)
346 if (ind
< 0 || (u_int
)ind
>= options
.num_host_key_files
)
348 return host_pubkeys
[ind
];
352 get_hostkey_index(struct sshkey
*key
, int compare
, struct ssh
*ssh
)
356 for (i
= 0; i
< options
.num_host_key_files
; i
++) {
357 if (sshkey_is_cert(key
)) {
358 if (key
== host_certificates
[i
] ||
359 (compare
&& host_certificates
[i
] &&
360 sshkey_equal(key
, host_certificates
[i
])))
363 if (key
== host_pubkeys
[i
] ||
364 (compare
&& host_pubkeys
[i
] &&
365 sshkey_equal(key
, host_pubkeys
[i
])))
375 fprintf(stderr
, "%s, %s\n", SSH_VERSION
, SSH_OPENSSL_VERSION
);
377 "usage: sshd [-46DdeGiqTtV] [-C connection_spec] [-c host_cert_file]\n"
378 " [-E log_file] [-f config_file] [-g login_grace_time]\n"
379 " [-h host_key_file] [-o option] [-p port] [-u len]\n"
385 parse_hostkeys(struct sshbuf
*hostkeys
)
393 while (sshbuf_len(hostkeys
) != 0) {
395 fatal_f("too many hostkeys");
396 host_pubkeys
= xrecallocarray(host_pubkeys
,
397 num_keys
, num_keys
+ 1, sizeof(*host_pubkeys
));
398 host_certificates
= xrecallocarray(host_certificates
,
399 num_keys
, num_keys
+ 1, sizeof(*host_certificates
));
402 if ((r
= sshbuf_get_string_direct(hostkeys
, &cp
, &len
)) != 0)
403 fatal_fr(r
, "extract pubkey");
404 if (len
!= 0 && (r
= sshkey_from_blob(cp
, len
, &k
)) != 0)
405 fatal_fr(r
, "parse pubkey");
406 host_pubkeys
[num_keys
] = k
;
408 debug2_f("key %u: %s", num_keys
, sshkey_ssh_name(k
));
411 if ((r
= sshbuf_get_string_direct(hostkeys
, &cp
, &len
)) != 0)
412 fatal_fr(r
, "extract pubkey");
413 if (len
!= 0 && (r
= sshkey_from_blob(cp
, len
, &k
)) != 0)
414 fatal_fr(r
, "parse pubkey");
415 host_certificates
[num_keys
] = k
;
417 debug2_f("cert %u: %s", num_keys
, sshkey_ssh_name(k
));
420 num_hostkeys
= num_keys
;
424 recv_privsep_state(struct ssh
*ssh
, struct sshbuf
*conf
,
425 uint64_t *timing_secretp
)
427 struct sshbuf
*hostkeys
;
431 mm_get_state(ssh
, &includes
, conf
, NULL
, timing_secretp
,
432 &hostkeys
, NULL
, NULL
, NULL
, NULL
);
433 parse_hostkeys(hostkeys
);
435 sshbuf_free(hostkeys
);
441 * Main program for the daemon.
444 main(int ac
, char **av
)
446 struct ssh
*ssh
= NULL
;
449 int r
, opt
, have_key
= 0;
450 int sock_in
= -1, sock_out
= -1, rexeced_flag
= 0;
451 char *line
, *logfile
= NULL
;
455 struct connection_info
*connection_info
= NULL
;
457 uint64_t timing_secret
= 0;
459 closefrom(PRIVSEP_MIN_FREE_FD
);
460 sigemptyset(&sigmask
);
461 sigprocmask(SIG_SETMASK
, &sigmask
, NULL
);
463 #ifdef HAVE_SECUREWARE
464 (void)set_auth_parameters(ac
, av
);
466 __progname
= ssh_get_progname(av
[0]);
468 /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
470 saved_argv
= xcalloc(ac
+ 1, sizeof(*saved_argv
));
471 for (i
= 0; (int)i
< ac
; i
++)
472 saved_argv
[i
] = xstrdup(av
[i
]);
473 saved_argv
[i
] = NULL
;
477 #ifndef HAVE_SETPROCTITLE
478 /* Prepare for later setproctitle emulation */
479 compat_init_setproctitle(ac
, av
);
483 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
486 /* Initialize configuration options to their default values. */
487 initialize_server_options(&options
);
489 /* Parse command-line arguments. */
490 while ((opt
= getopt(ac
, av
,
491 "C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) {
494 options
.address_family
= AF_INET
;
497 options
.address_family
= AF_INET6
;
500 config_file_name
= optarg
;
503 servconf_add_hostcert("[command-line]", 0,
507 if (debug_flag
== 0) {
509 options
.log_level
= SYSLOG_LEVEL_DEBUG1
;
510 } else if (options
.log_level
< SYSLOG_LEVEL_DEBUG3
)
535 options
.log_level
= SYSLOG_LEVEL_QUIET
;
538 /* protocol 1, ignored */
541 options
.ports_from_cmdline
= 1;
542 if (options
.num_ports
>= MAX_PORTS
) {
543 fprintf(stderr
, "too many ports.\n");
546 options
.ports
[options
.num_ports
++] = a2port(optarg
);
547 if (options
.ports
[options
.num_ports
-1] <= 0) {
548 fprintf(stderr
, "Bad port number.\n");
553 if ((options
.login_grace_time
= convtime(optarg
)) == -1) {
554 fprintf(stderr
, "Invalid login grace time.\n");
559 /* protocol 1, ignored */
562 servconf_add_hostkey("[command-line]", 0,
563 &options
, optarg
, 1);
568 fatal("test/dump modes not supported");
571 connection_info
= server_get_connection_info(ssh
, 0, 0);
572 if (parse_server_match_testspec(connection_info
,
577 utmp_len
= (u_int
)strtonum(optarg
, 0, HOST_NAME_MAX
+1+1, NULL
);
578 if (utmp_len
> HOST_NAME_MAX
+1) {
579 fprintf(stderr
, "Invalid utmp length.\n");
584 line
= xstrdup(optarg
);
585 if (process_server_config_line(&options
, line
,
586 "command-line", 0, NULL
, NULL
, &includes
) != 0)
591 fprintf(stderr
, "%s, %s\n",
592 SSH_VERSION
, SSH_OPENSSL_VERSION
);
601 fatal("sshd-auth should not be executed directly");
604 OpenSSL_add_all_algorithms();
607 /* If requested, redirect the logs to the specified logfile. */
608 if (logfile
!= NULL
) {
611 snprintf(pid_s
, sizeof(pid_s
), "%ld", (unsigned long)getpid());
612 cp
= percent_expand(logfile
,
616 log_redirect_stderr_to(cp
);
621 options
.log_level
== SYSLOG_LEVEL_NOT_SET
?
622 SYSLOG_LEVEL_INFO
: options
.log_level
,
623 options
.log_facility
== SYSLOG_FACILITY_NOT_SET
?
624 SYSLOG_FACILITY_AUTH
: options
.log_facility
, 1);
626 /* XXX can't use monitor_init(); it makes fds */
627 pmonitor
= xcalloc(1, sizeof(*pmonitor
));
628 pmonitor
->m_sendfd
= pmonitor
->m_log_recvfd
= -1;
629 pmonitor
->m_recvfd
= PRIVSEP_MONITOR_FD
;
630 pmonitor
->m_log_sendfd
= PRIVSEP_LOG_FD
;
631 set_log_handler(mm_log_handler
, pmonitor
);
633 /* Check that there are no remaining arguments. */
635 fprintf(stderr
, "Extra argument %s.\n", av
[optind
]);
639 debug("sshd version %s, %s", SSH_VERSION
, SSH_OPENSSL_VERSION
);
641 /* Connection passed by stdin/out */
644 * NB. must be different fd numbers for the !socket case,
645 * as packet_connection_is_on_socket() depends on this.
647 sock_in
= dup(STDIN_FILENO
);
648 sock_out
= dup(STDOUT_FILENO
);
650 /* rexec case; accept()ed socket in ancestor listener */
651 sock_in
= sock_out
= dup(STDIN_FILENO
);
654 if (stdfd_devnull(1, 1, 0) == -1)
655 error("stdfd_devnull failed");
656 debug("network sockets: %d, %d", sock_in
, sock_out
);
659 * Register our connection. This turns encryption off because we do
662 if ((ssh
= ssh_packet_set_connection(NULL
, sock_in
, sock_out
)) == NULL
)
663 fatal("Unable to create connection");
664 the_active_state
= ssh
;
665 ssh_packet_set_server(ssh
);
666 pmonitor
->m_pkex
= &ssh
->kex
;
668 /* Fetch our configuration */
669 if ((cfg
= sshbuf_new()) == NULL
)
670 fatal("sshbuf_new config buf failed");
671 setproctitle("%s", "[session-auth early]");
672 recv_privsep_state(ssh
, cfg
, &timing_secret
);
673 parse_server_config(&options
, "rexec", cfg
, &includes
, NULL
, 1);
674 /* Fill in default values for those options not explicitly set. */
675 fill_default_server_options(&options
);
676 options
.timing_secret
= timing_secret
; /* XXX eliminate from unpriv */
678 /* Store privilege separation user for later use if required. */
679 privsep_chroot
= (getuid() == 0 || geteuid() == 0);
680 if ((privsep_pw
= getpwnam(SSH_PRIVSEP_USER
)) == NULL
) {
681 if (privsep_chroot
|| options
.kerberos_authentication
)
682 fatal("Privilege separation user %s does not exist",
685 privsep_pw
= pwcopy(privsep_pw
);
686 freezero(privsep_pw
->pw_passwd
, strlen(privsep_pw
->pw_passwd
));
687 privsep_pw
->pw_passwd
= xstrdup("*");
692 if (options
.moduli_file
!= NULL
)
693 dh_set_moduli_file(options
.moduli_file
);
696 if (options
.host_key_agent
) {
697 if (strcmp(options
.host_key_agent
, SSH_AUTHSOCKET_ENV_NAME
))
698 setenv(SSH_AUTHSOCKET_ENV_NAME
,
699 options
.host_key_agent
, 1);
700 if ((r
= ssh_get_authentication_socket(NULL
)) == 0)
703 error_r(r
, "Could not connect to agent \"%s\"",
704 options
.host_key_agent
);
707 if (options
.num_host_key_files
!= num_hostkeys
) {
708 fatal("internal error: hostkeys confused (config %u recvd %u)",
709 options
.num_host_key_files
, num_hostkeys
);
712 for (i
= 0; i
< options
.num_host_key_files
; i
++) {
713 if (host_pubkeys
[i
] != NULL
) {
719 fatal("internal error: received no hostkeys");
721 /* Ensure that umask disallows at least group and world write */
722 new_umask
= umask(0077) | 0022;
723 (void) umask(new_umask
);
725 /* Initialize the log (it is reinitialized below in case we forked). */
726 log_init(__progname
, options
.log_level
, options
.log_facility
, 1);
727 set_log_handler(mm_log_handler
, pmonitor
);
728 for (i
= 0; i
< options
.num_log_verbose
; i
++)
729 log_verbose_add(options
.log_verbose
[i
]);
732 * Chdir to the root directory so that the current disk can be
733 * unmounted if desired.
735 if (chdir("/") == -1)
736 error("chdir(\"/\"): %s", strerror(errno
));
738 /* This is the child authenticating a new connection. */
739 setproctitle("%s", "[session-auth]");
741 /* Executed child processes don't need these. */
742 fcntl(sock_out
, F_SETFD
, FD_CLOEXEC
);
743 fcntl(sock_in
, F_SETFD
, FD_CLOEXEC
);
745 ssh_signal(SIGPIPE
, SIG_IGN
);
746 ssh_signal(SIGALRM
, SIG_DFL
);
747 ssh_signal(SIGHUP
, SIG_DFL
);
748 ssh_signal(SIGTERM
, SIG_DFL
);
749 ssh_signal(SIGQUIT
, SIG_DFL
);
750 ssh_signal(SIGCHLD
, SIG_DFL
);
752 /* Prepare the channels layer */
753 channel_init_channels(ssh
);
754 channel_set_af(ssh
, options
.address_family
);
755 server_process_channel_timeouts(ssh
);
756 server_process_permitopen(ssh
);
758 ssh_packet_set_nonblocking(ssh
);
760 /* allocate authentication context */
761 authctxt
= xcalloc(1, sizeof(*authctxt
));
762 ssh
->authctxt
= authctxt
;
764 /* XXX global for cleanup, access from other modules */
765 the_authctxt
= authctxt
;
767 /* Set default key authentication options */
768 if ((auth_opts
= sshauthopt_new_with_keys_defaults()) == NULL
)
769 fatal("allocation failed");
771 /* prepare buffer to collect messages to display to user after login */
772 if ((loginmsg
= sshbuf_new()) == NULL
)
773 fatal("sshbuf_new loginmsg failed");
776 /* Enable challenge-response authentication for privilege separation */
777 privsep_challenge_enable();
780 /* Cache supported mechanism OIDs for later use */
781 ssh_gssapi_prepare_supported_oids();
784 privsep_child_demote();
786 /* perform the key exchange */
787 /* authenticate user and start session */
789 do_authentication2(ssh
);
792 * The unprivileged child now transfers the current keystate and exits.
794 mm_send_keystate(ssh
, pmonitor
);
795 ssh_packet_clear_keys(ssh
);
800 sshd_hostkey_sign(struct ssh
*ssh
, struct sshkey
*privkey
,
801 struct sshkey
*pubkey
, u_char
**signature
, size_t *slenp
,
802 const u_char
*data
, size_t dlen
, const char *alg
)
805 if (mm_sshkey_sign(ssh
, privkey
, signature
, slenp
,
806 data
, dlen
, alg
, options
.sk_provider
, NULL
,
808 fatal_f("privkey sign failed");
810 if (mm_sshkey_sign(ssh
, pubkey
, signature
, slenp
,
811 data
, dlen
, alg
, options
.sk_provider
, NULL
,
813 fatal_f("pubkey sign failed");
818 /* SSH2 key exchange */
820 do_ssh2_kex(struct ssh
*ssh
)
822 char *hkalgs
= NULL
, *myproposal
[PROPOSAL_MAX
];
823 const char *compression
= NULL
;
827 if (options
.rekey_limit
|| options
.rekey_interval
)
828 ssh_packet_set_rekey_limits(ssh
, options
.rekey_limit
,
829 options
.rekey_interval
);
831 if (options
.compression
== COMP_NONE
)
832 compression
= "none";
833 hkalgs
= list_hostkey_types();
835 kex_proposal_populate_entries(ssh
, myproposal
, options
.kex_algorithms
,
836 options
.ciphers
, options
.macs
, compression
, hkalgs
);
840 /* start key exchange */
841 if ((r
= kex_setup(ssh
, myproposal
)) != 0)
842 fatal_r(r
, "kex_setup");
843 kex_set_server_sig_algs(ssh
, options
.pubkey_accepted_algos
);
847 kex
->kex
[KEX_DH_GRP1_SHA1
] = kex_gen_server
;
848 kex
->kex
[KEX_DH_GRP14_SHA1
] = kex_gen_server
;
849 kex
->kex
[KEX_DH_GRP14_SHA256
] = kex_gen_server
;
850 kex
->kex
[KEX_DH_GRP16_SHA512
] = kex_gen_server
;
851 kex
->kex
[KEX_DH_GRP18_SHA512
] = kex_gen_server
;
852 kex
->kex
[KEX_DH_GEX_SHA1
] = kexgex_server
;
853 kex
->kex
[KEX_DH_GEX_SHA256
] = kexgex_server
;
854 # ifdef OPENSSL_HAS_ECC
855 kex
->kex
[KEX_ECDH_SHA2
] = kex_gen_server
;
856 # endif /* OPENSSL_HAS_ECC */
857 #endif /* WITH_OPENSSL */
858 kex
->kex
[KEX_C25519_SHA256
] = kex_gen_server
;
859 kex
->kex
[KEX_KEM_SNTRUP761X25519_SHA512
] = kex_gen_server
;
860 kex
->kex
[KEX_KEM_MLKEM768X25519_SHA256
] = kex_gen_server
;
861 kex
->load_host_public_key
=&get_hostkey_public_by_type
;
862 kex
->load_host_private_key
=&get_hostkey_private_by_type
;
863 kex
->host_key_index
=&get_hostkey_index
;
864 kex
->sign
= sshd_hostkey_sign
;
866 ssh_dispatch_run_fatal(ssh
, DISPATCH_BLOCK
, &kex
->done
);
867 kex_proposal_free_entries(myproposal
);
870 /* send 1st encrypted/maced/compressed message */
871 if ((r
= sshpkt_start(ssh
, SSH2_MSG_IGNORE
)) != 0 ||
872 (r
= sshpkt_put_cstring(ssh
, "markus")) != 0 ||
873 (r
= sshpkt_send(ssh
)) != 0 ||
874 (r
= ssh_packet_write_wait(ssh
)) != 0)
875 fatal_fr(r
, "send test");
880 /* server specific fatal cleanup */