diff options
Diffstat (limited to 'sshserver.c')
-rw-r--r-- | sshserver.c | 591 |
1 files changed, 0 insertions, 591 deletions
diff --git a/sshserver.c b/sshserver.c deleted file mode 100644 index cc1c880d..00000000 --- a/sshserver.c +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Top-level code for SSH server implementation. - */ - -#include <assert.h> -#include <stddef.h> - -#include "putty.h" -#include "ssh.h" -#include "sshbpp.h" -#include "sshppl.h" -#include "sshchan.h" -#include "sshserver.h" -#ifndef NO_GSSAPI -#include "sshgssc.h" -#include "sshgss.h" -#endif - -struct Ssh { int dummy; }; - -typedef struct server server; -struct server { - bufchain in_raw, out_raw; - IdempotentCallback ic_out_raw; - bool pending_close; - - bufchain dummy_user_input; /* we never put anything on this */ - - PacketLogSettings pls; - LogContext *logctx; - struct DataTransferStats stats; - - int remote_bugs; - - Socket *socket; - Plug plug; - int conn_throttle_count; - bool frozen; - - Conf *conf; - const SshServerConfig *ssc; - ssh_key *const *hostkeys; - int nhostkeys; - RSAKey *hostkey1; - AuthPolicy *authpolicy; - LogPolicy *logpolicy; - const SftpServerVtable *sftpserver_vt; - - agentfwd *stunt_agentfwd; - - Seat seat; - Ssh ssh; - struct ssh_version_receiver version_receiver; - - BinaryPacketProtocol *bpp; - PacketProtocolLayer *base_layer; - ConnectionLayer *cl; - -#ifndef NO_GSSAPI - struct ssh_connection_shared_gss_state gss_state; -#endif -}; - -static void ssh_server_free_callback(void *vsrv); -static void server_got_ssh_version(struct ssh_version_receiver *rcv, - int major_version); -static void server_connect_bpp(server *srv); -static void server_bpp_output_raw_data_callback(void *vctx); - -void share_activate(ssh_sharing_state *sharestate, - const char *server_verstring) {} -void ssh_connshare_provide_connlayer(ssh_sharing_state *sharestate, - ConnectionLayer *cl) {} -int share_ndownstreams(ssh_sharing_state *sharestate) { return 0; } -void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type, - const void *vpkt, int pktlen) {} -void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan, - unsigned upstream_id, unsigned server_id, - unsigned server_currwin, unsigned server_maxpkt, - unsigned client_adjusted_window, - const char *peer_addr, int peer_port, int endian, - int protomajor, int protominor, - const void *initial_data, int initial_len) {} -Channel *agentf_new(SshChannel *c) { return NULL; } -bool agent_exists(void) { return false; } -void ssh_got_exitcode(Ssh *ssh, int exitcode) {} -void ssh_check_frozen(Ssh *ssh) {} - -mainchan *mainchan_new( - PacketProtocolLayer *ppl, ConnectionLayer *cl, Conf *conf, - int term_width, int term_height, bool is_simple, SshChannel **sc_out) -{ return NULL; } -void mainchan_get_specials( - mainchan *mc, add_special_fn_t add_special, void *ctx) {} -void mainchan_special_cmd(mainchan *mc, SessionSpecialCode code, int arg) {} -void mainchan_terminal_size(mainchan *mc, int width, int height) {} - -/* Seat functions to ensure we don't get choosy about crypto - as the - * server, it's not up to us to give user warnings */ -static int server_confirm_weak_crypto_primitive( - Seat *seat, const char *algtype, const char *algname, - void (*callback)(void *ctx, int result), void *ctx) { return 1; } -static int server_confirm_weak_cached_hostkey( - Seat *seat, const char *algname, const char *betteralgs, - void (*callback)(void *ctx, int result), void *ctx) { return 1; } - -static const SeatVtable server_seat_vt = { - .output = nullseat_output, - .eof = nullseat_eof, - .get_userpass_input = nullseat_get_userpass_input, - .notify_remote_exit = nullseat_notify_remote_exit, - .connection_fatal = nullseat_connection_fatal, - .update_specials_menu = nullseat_update_specials_menu, - .get_ttymode = nullseat_get_ttymode, - .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = nullseat_verify_ssh_host_key, - .confirm_weak_crypto_primitive = server_confirm_weak_crypto_primitive, - .confirm_weak_cached_hostkey = server_confirm_weak_cached_hostkey, - .is_utf8 = nullseat_is_never_utf8, - .echoedit_update = nullseat_echoedit_update, - .get_x_display = nullseat_get_x_display, - .get_windowid = nullseat_get_windowid, - .get_window_pixel_size = nullseat_get_window_pixel_size, - .stripctrl_new = nullseat_stripctrl_new, - .set_trust_status = nullseat_set_trust_status, - .verbose = nullseat_verbose_no, - .interactive = nullseat_interactive_no, - .get_cursor_position = nullseat_get_cursor_position, -}; - -static void server_socket_log(Plug *plug, PlugLogType type, SockAddr *addr, - int port, const char *error_msg, int error_code) -{ - /* server *srv = container_of(plug, server, plug); */ - /* FIXME */ -} - -static void server_closing(Plug *plug, const char *error_msg, int error_code, - bool calling_back) -{ - server *srv = container_of(plug, server, plug); - if (error_msg) { - ssh_remote_error(&srv->ssh, "%s", error_msg); - } else if (srv->bpp) { - srv->bpp->input_eof = true; - queue_idempotent_callback(&srv->bpp->ic_in_raw); - } -} - -static void server_receive( - Plug *plug, int urgent, const char *data, size_t len) -{ - server *srv = container_of(plug, server, plug); - - /* Log raw data, if we're in that mode. */ - if (srv->logctx) - log_packet(srv->logctx, PKT_INCOMING, -1, NULL, data, len, - 0, NULL, NULL, 0, NULL); - - bufchain_add(&srv->in_raw, data, len); - if (!srv->frozen && srv->bpp) - queue_idempotent_callback(&srv->bpp->ic_in_raw); -} - -static void server_sent(Plug *plug, size_t bufsize) -{ -#ifdef FIXME - server *srv = container_of(plug, server, plug); - - /* - * If the send backlog on the SSH socket itself clears, we should - * unthrottle the whole world if it was throttled. Also trigger an - * extra call to the consumer of the BPP's output, to try to send - * some more data off its bufchain. - */ - if (bufsize < SSH_MAX_BACKLOG) { - srv_throttle_all(srv, 0, bufsize); - queue_idempotent_callback(&srv->ic_out_raw); - } -#endif -} - -LogContext *ssh_get_logctx(Ssh *ssh) -{ - server *srv = container_of(ssh, server, ssh); - return srv->logctx; -} - -void ssh_throttle_conn(Ssh *ssh, int adjust) -{ - server *srv = container_of(ssh, server, ssh); - int old_count = srv->conn_throttle_count; - bool frozen; - - srv->conn_throttle_count += adjust; - assert(srv->conn_throttle_count >= 0); - - if (srv->conn_throttle_count && !old_count) { - frozen = true; - } else if (!srv->conn_throttle_count && old_count) { - frozen = false; - } else { - return; /* don't change current frozen state */ - } - - srv->frozen = frozen; - - if (srv->socket) { - sk_set_frozen(srv->socket, frozen); - - /* - * Now process any SSH connection data that was stashed in our - * queue while we were frozen. - */ - queue_idempotent_callback(&srv->bpp->ic_in_raw); - } -} - -void ssh_conn_processed_data(Ssh *ssh) -{ - /* FIXME: we could add the same check_frozen_state system as we - * have in ssh.c, but because that was originally added to work - * around a peculiarity of the GUI event loop, I haven't yet. */ -} - -Conf *make_ssh_server_conf(void) -{ - Conf *conf = conf_new(); - load_open_settings(NULL, conf); - /* In Uppity, we support even the legacy des-cbc cipher by - * default, so that it will be available if the user forces it by - * overriding the KEXINIT strings. If the user wants it _not_ - * supported, of course, they can override KEXINIT in the other - * direction. */ - conf_set_bool(conf, CONF_ssh2_des_cbc, true); - return conf; -} - -static const PlugVtable ssh_server_plugvt = { - .log = server_socket_log, - .closing = server_closing, - .receive = server_receive, - .sent = server_sent, -}; - -Plug *ssh_server_plug( - Conf *conf, const SshServerConfig *ssc, - ssh_key *const *hostkeys, int nhostkeys, - RSAKey *hostkey1, AuthPolicy *authpolicy, LogPolicy *logpolicy, - const SftpServerVtable *sftpserver_vt) -{ - server *srv = snew(server); - - memset(srv, 0, sizeof(server)); - - srv->plug.vt = &ssh_server_plugvt; - srv->conf = conf_copy(conf); - srv->ssc = ssc; - srv->logctx = log_init(logpolicy, conf); - conf_set_bool(srv->conf, CONF_ssh_no_shell, true); - srv->nhostkeys = nhostkeys; - srv->hostkeys = hostkeys; - srv->hostkey1 = hostkey1; - srv->authpolicy = authpolicy; - srv->logpolicy = logpolicy; - srv->sftpserver_vt = sftpserver_vt; - - srv->seat.vt = &server_seat_vt; - - bufchain_init(&srv->in_raw); - bufchain_init(&srv->out_raw); - bufchain_init(&srv->dummy_user_input); - -#ifndef NO_GSSAPI - /* FIXME: replace with sensible */ - srv->gss_state.libs = snew(struct ssh_gss_liblist); - srv->gss_state.libs->nlibraries = 0; -#endif - - return &srv->plug; -} - -void ssh_server_start(Plug *plug, Socket *socket) -{ - server *srv = container_of(plug, server, plug); - const char *our_protoversion; - - if (srv->ssc->bare_connection) { - our_protoversion = "2.0"; /* SSH-2 only */ - } else if (srv->hostkey1 && srv->nhostkeys) { - our_protoversion = "1.99"; /* offer both SSH-1 and SSH-2 */ - } else if (srv->hostkey1) { - our_protoversion = "1.5"; /* SSH-1 only */ - } else { - assert(srv->nhostkeys); - our_protoversion = "2.0"; /* SSH-2 only */ - } - - srv->socket = socket; - - srv->ic_out_raw.fn = server_bpp_output_raw_data_callback; - srv->ic_out_raw.ctx = srv; - srv->version_receiver.got_ssh_version = server_got_ssh_version; - srv->bpp = ssh_verstring_new( - srv->conf, srv->logctx, srv->ssc->bare_connection, - our_protoversion, &srv->version_receiver, - true, srv->ssc->application_name); - server_connect_bpp(srv); - queue_idempotent_callback(&srv->bpp->ic_in_raw); -} - -static void ssh_server_free_callback(void *vsrv) -{ - server *srv = (server *)vsrv; - - logeventf(srv->logctx, "freeing server instance"); - - bufchain_clear(&srv->in_raw); - bufchain_clear(&srv->out_raw); - bufchain_clear(&srv->dummy_user_input); - - if (srv->socket) - sk_close(srv->socket); - - if (srv->stunt_agentfwd) - agentfwd_free(srv->stunt_agentfwd); - - if (srv->base_layer) - ssh_ppl_free(srv->base_layer); - if (srv->bpp) - ssh_bpp_free(srv->bpp); - - delete_callbacks_for_context(srv); - - conf_free(srv->conf); - log_free(srv->logctx); - -#ifndef NO_GSSAPI - sfree(srv->gss_state.libs); /* FIXME: replace with sensible */ -#endif - - LogPolicy *lp = srv->logpolicy; - sfree(srv); - - server_instance_terminated(lp); -} - -static void server_connect_bpp(server *srv) -{ - srv->bpp->ssh = &srv->ssh; - srv->bpp->in_raw = &srv->in_raw; - srv->bpp->out_raw = &srv->out_raw; - bufchain_set_callback(srv->bpp->out_raw, &srv->ic_out_raw); - srv->bpp->pls = &srv->pls; - srv->bpp->logctx = srv->logctx; - srv->bpp->remote_bugs = srv->remote_bugs; - /* Servers don't really have a notion of 'unexpected' connection - * closure. The client is free to close if it likes. */ - srv->bpp->expect_close = true; -} - -static void server_connect_ppl(server *srv, PacketProtocolLayer *ppl) -{ - ppl->bpp = srv->bpp; - ppl->user_input = &srv->dummy_user_input; - ppl->logctx = srv->logctx; - ppl->ssh = &srv->ssh; - ppl->seat = &srv->seat; - ppl->remote_bugs = srv->remote_bugs; -} - -static void server_bpp_output_raw_data_callback(void *vctx) -{ - server *srv = (server *)vctx; - - if (!srv->socket) - return; - - while (bufchain_size(&srv->out_raw) > 0) { - size_t backlog; - - ptrlen data = bufchain_prefix(&srv->out_raw); - - if (srv->logctx) - log_packet(srv->logctx, PKT_OUTGOING, -1, NULL, data.ptr, data.len, - 0, NULL, NULL, 0, NULL); - backlog = sk_write(srv->socket, data.ptr, data.len); - - bufchain_consume(&srv->out_raw, data.len); - - if (backlog > SSH_MAX_BACKLOG) { -#ifdef FIXME - ssh_throttle_all(ssh, 1, backlog); -#endif - return; - } - } - - if (srv->pending_close) { - sk_close(srv->socket); - srv->socket = NULL; - queue_toplevel_callback(ssh_server_free_callback, srv); - } -} - -static void server_shutdown_internal(server *srv) -{ - /* - * We only need to free the base PPL, which will free the others - * (if any) transitively. - */ - if (srv->base_layer) { - ssh_ppl_free(srv->base_layer); - srv->base_layer = NULL; - } - - srv->cl = NULL; -} - -static void server_initiate_connection_close(server *srv) -{ - /* Wind up everything above the BPP. */ - server_shutdown_internal(srv); - - /* Force any remaining queued SSH packets through the BPP, and - * schedule closing the network socket after they go out. */ - ssh_bpp_handle_output(srv->bpp); - srv->pending_close = true; - queue_idempotent_callback(&srv->ic_out_raw); - - /* Now we expect the other end to close the connection too in - * response, so arrange that we'll receive notification of that - * via ssh_remote_eof. */ - srv->bpp->expect_close = true; -} - -#define GET_FORMATTED_MSG(fmt) \ - char *msg; \ - va_list ap; \ - va_start(ap, fmt); \ - msg = dupvprintf(fmt, ap); \ - va_end(ap); - -#define LOG_FORMATTED_MSG(logctx, fmt) do \ - { \ - va_list ap; \ - va_start(ap, fmt); \ - logeventvf(logctx, fmt, ap); \ - va_end(ap); \ - } while (0) - -void ssh_remote_error(Ssh *ssh, const char *fmt, ...) -{ - server *srv = container_of(ssh, server, ssh); - LOG_FORMATTED_MSG(srv->logctx, fmt); - queue_toplevel_callback(ssh_server_free_callback, srv); -} - -void ssh_remote_eof(Ssh *ssh, const char *fmt, ...) -{ - server *srv = container_of(ssh, server, ssh); - LOG_FORMATTED_MSG(srv->logctx, fmt); - queue_toplevel_callback(ssh_server_free_callback, srv); -} - -void ssh_proto_error(Ssh *ssh, const char *fmt, ...) -{ - server *srv = container_of(ssh, server, ssh); - if (srv->base_layer) { - GET_FORMATTED_MSG(fmt); - ssh_bpp_queue_disconnect(srv->bpp, msg, - SSH2_DISCONNECT_PROTOCOL_ERROR); - server_initiate_connection_close(srv); - logeventf(srv->logctx, "Protocol error: %s", msg); - sfree(msg); - } -} - -void ssh_sw_abort(Ssh *ssh, const char *fmt, ...) -{ - server *srv = container_of(ssh, server, ssh); - LOG_FORMATTED_MSG(srv->logctx, fmt); - queue_toplevel_callback(ssh_server_free_callback, srv); -} - -void ssh_user_close(Ssh *ssh, const char *fmt, ...) -{ - server *srv = container_of(ssh, server, ssh); - LOG_FORMATTED_MSG(srv->logctx, fmt); - queue_toplevel_callback(ssh_server_free_callback, srv); -} - -static void server_got_ssh_version(struct ssh_version_receiver *rcv, - int major_version) -{ - server *srv = container_of(rcv, server, version_receiver); - BinaryPacketProtocol *old_bpp; - PacketProtocolLayer *connection_layer; - - old_bpp = srv->bpp; - srv->remote_bugs = ssh_verstring_get_bugs(old_bpp); - - if (srv->ssc->bare_connection) { - srv->bpp = ssh2_bare_bpp_new(srv->logctx); - server_connect_bpp(srv); - - connection_layer = ssh2_connection_new( - &srv->ssh, NULL, false, srv->conf, - ssh_verstring_get_local(old_bpp), &srv->cl); - ssh2connection_server_configure(connection_layer, - srv->sftpserver_vt, srv->ssc); - server_connect_ppl(srv, connection_layer); - - srv->base_layer = connection_layer; - } else if (major_version == 2) { - PacketProtocolLayer *userauth_layer, *transport_child_layer; - - srv->bpp = ssh2_bpp_new(srv->logctx, &srv->stats, true); - server_connect_bpp(srv); - - connection_layer = ssh2_connection_new( - &srv->ssh, NULL, false, srv->conf, - ssh_verstring_get_local(old_bpp), &srv->cl); - ssh2connection_server_configure(connection_layer, - srv->sftpserver_vt, srv->ssc); - server_connect_ppl(srv, connection_layer); - - if (conf_get_bool(srv->conf, CONF_ssh_no_userauth)) { - userauth_layer = NULL; - transport_child_layer = connection_layer; - } else { - userauth_layer = ssh2_userauth_server_new( - connection_layer, srv->authpolicy, srv->ssc); - server_connect_ppl(srv, userauth_layer); - transport_child_layer = userauth_layer; - } - - srv->base_layer = ssh2_transport_new( - srv->conf, NULL, 0, NULL, - ssh_verstring_get_remote(old_bpp), - ssh_verstring_get_local(old_bpp), -#ifndef NO_GSSAPI - &srv->gss_state, -#else - NULL, -#endif - &srv->stats, transport_child_layer, srv->ssc); - ssh2_transport_provide_hostkeys( - srv->base_layer, srv->hostkeys, srv->nhostkeys); - if (userauth_layer) - ssh2_userauth_server_set_transport_layer( - userauth_layer, srv->base_layer); - server_connect_ppl(srv, srv->base_layer); - - } else { - srv->bpp = ssh1_bpp_new(srv->logctx); - server_connect_bpp(srv); - - connection_layer = ssh1_connection_new(&srv->ssh, srv->conf, &srv->cl); - ssh1connection_server_configure(connection_layer, srv->ssc); - server_connect_ppl(srv, connection_layer); - - srv->base_layer = ssh1_login_server_new( - connection_layer, srv->hostkey1, srv->authpolicy, srv->ssc); - server_connect_ppl(srv, srv->base_layer); - } - - /* Connect the base layer - whichever it is - to the BPP, and set - * up its selfptr. */ - srv->base_layer->selfptr = &srv->base_layer; - ssh_ppl_setup_queues(srv->base_layer, &srv->bpp->in_pq, &srv->bpp->out_pq); - -#ifdef FIXME // we probably will want one of these, in the end - srv->pinger = pinger_new(srv->conf, &srv->backend); -#endif - - if (srv->ssc->stunt_open_unconditional_agent_socket) { - char *socketname; - srv->stunt_agentfwd = agentfwd_new(srv->cl, &socketname); - if (srv->stunt_agentfwd) { - logeventf(srv->logctx, "opened unconditional agent socket at %s\n", - socketname); - sfree(socketname); - } - } - - queue_idempotent_callback(&srv->bpp->ic_in_raw); - ssh_ppl_process_queue(srv->base_layer); - - ssh_bpp_free(old_bpp); -} |