diff --git a/monitor.c b/monitor.c index 9d6672bb6..73a85408e 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.255 2026/03/28 05:06:16 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.256 2026/05/31 11:30:50 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -592,34 +592,26 @@ monitor_reset_key_state(void) int mm_answer_state(struct ssh *ssh, int sock, struct sshbuf *unused) { - struct sshbuf *m = NULL, *inc = NULL, *hostkeys = NULL; + struct sshbuf *m = NULL, *config = NULL, *hostkeys = NULL; struct sshbuf *opts = NULL, *confdata = NULL; - struct include_item *item = NULL; int postauth; int r; debug_f("config len %zu", sshbuf_len(cfg)); if ((m = sshbuf_new()) == NULL || - (inc = sshbuf_new()) == NULL || + (config = sshbuf_new()) == NULL || (opts = sshbuf_new()) == NULL || (confdata = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); - /* XXX unnecessary? */ - /* pack includes into a string */ - TAILQ_FOREACH(item, &includes, entry) { - if ((r = sshbuf_put_cstring(inc, item->selector)) != 0 || - (r = sshbuf_put_cstring(inc, item->filename)) != 0 || - (r = sshbuf_put_stringb(inc, item->contents)) != 0) - fatal_fr(r, "compose includes"); - } - hostkeys = pack_hostkeys(); + if ((r = serialise_server_options(&options, &config)) != 0) + fatal_fr(r, "serialise_server_options"); /* * Protocol from monitor to unpriv privsep process: - * string configuration + * string configuration_blob * uint64 timing_secret XXX move delays to monitor and remove * string host_keys[] { * string public_key @@ -627,23 +619,17 @@ mm_answer_state(struct ssh *ssh, int sock, struct sshbuf *unused) * } * string server_banner * string client_banner - * string included_files[] { - * string selector - * string filename - * string contents - * } * string configuration_data (postauth) * string keystate (postauth) * string authenticated_user (postauth) * string session_info (postauth) * string authopts (postauth) */ - if ((r = sshbuf_put_stringb(m, cfg)) != 0 || + if ((r = sshbuf_put_stringb(m, config)) != 0 || (r = sshbuf_put_u64(m, options.timing_secret)) != 0 || (r = sshbuf_put_stringb(m, hostkeys)) != 0 || (r = sshbuf_put_stringb(m, ssh->kex->server_version)) != 0 || - (r = sshbuf_put_stringb(m, ssh->kex->client_version)) != 0 || - (r = sshbuf_put_stringb(m, inc)) != 0) + (r = sshbuf_put_stringb(m, ssh->kex->client_version)) != 0) fatal_fr(r, "compose config"); postauth = (authctxt && authctxt->pw && authctxt->authenticated); @@ -652,7 +638,7 @@ mm_answer_state(struct ssh *ssh, int sock, struct sshbuf *unused) fatal_f("internal error: called in postauth"); } - sshbuf_free(inc); + sshbuf_free(config); sshbuf_free(opts); sshbuf_free(confdata); sshbuf_free(hostkeys); @@ -832,27 +818,15 @@ void mm_encode_server_options(struct sshbuf *m) { int r; - u_int i; + struct sshbuf *config; - /* XXX this leaks raw pointers to the unpriv child processes */ - if ((r = sshbuf_put_string(m, &options, sizeof(options))) != 0) + if ((config = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = serialise_server_options(&options, &config)) != 0) + fatal_fr(r, "serialise_server_options"); + if ((r = sshbuf_put_stringb(m, config)) != 0) fatal_fr(r, "assemble options"); - -#define M_CP_STROPT(x) do { \ - if (options.x != NULL && \ - (r = sshbuf_put_cstring(m, options.x)) != 0) \ - fatal_fr(r, "assemble %s", #x); \ - } while (0) -#define M_CP_STRARRAYOPT(x, nx, clobber) do { \ - for (i = 0; i < options.nx; i++) { \ - if ((r = sshbuf_put_cstring(m, options.x[i])) != 0) \ - fatal_fr(r, "assemble %s", #x); \ - } \ - } while (0) - /* See comment in servconf.h */ - COPY_MATCH_STRING_OPTS(); -#undef M_CP_STROPT -#undef M_CP_STRARRAYOPT + sshbuf_free(config); } /* Retrieves the password entry and also checks if the user is permitted */ diff --git a/monitor_wrap.c b/monitor_wrap.c index 81596a4cc..e2b9a2802 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.146 2026/03/02 02:40:15 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.147 2026/05/31 11:30:50 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -302,55 +302,20 @@ mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp, void mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m) { - const u_char *p; - size_t len; - u_int i; - ServerOptions *newopts; + struct sshbuf *config; int r; + u_int i; - if ((r = sshbuf_get_string_direct(m, &p, &len)) != 0) + if ((r = sshbuf_froms(m, &config)) != 0) fatal_fr(r, "parse opts"); - if (len != sizeof(*newopts)) - fatal_f("option block size mismatch"); - newopts = xcalloc(sizeof(*newopts), 1); - memcpy(newopts, p, sizeof(*newopts)); + if ((r = deserialise_server_options(config, &options)) != 0) + fatal_fr(r, "deserialise_server_options"); + sshbuf_free(config); -#define M_CP_STROPT(x) do { \ - if (newopts->x != NULL && \ - (r = sshbuf_get_cstring(m, &newopts->x, NULL)) != 0) \ - fatal_fr(r, "parse %s", #x); \ - } while (0) -#define M_CP_STRARRAYOPT(x, nx, clobber) do { \ - newopts->x = newopts->nx == 0 ? \ - NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \ - for (i = 0; i < newopts->nx; i++) { \ - if ((r = sshbuf_get_cstring(m, \ - &newopts->x[i], NULL)) != 0) \ - fatal_fr(r, "parse %s", #x); \ - } \ - } while (0) - /* See comment in servconf.h */ - COPY_MATCH_STRING_OPTS(); -#undef M_CP_STROPT -#undef M_CP_STRARRAYOPT - - copy_set_server_options(&options, newopts, 1); log_change_level(options.log_level); log_verbose_reset(); for (i = 0; i < options.num_log_verbose; i++) log_verbose_add(options.log_verbose[i]); - - /* use the macro hell to clean up too */ -#define M_CP_STROPT(x) free(newopts->x) -#define M_CP_STRARRAYOPT(x, nx, clobber) do { \ - for (i = 0; i < newopts->nx; i++) \ - free(newopts->x[i]); \ - free(newopts->x); \ - } while (0) - COPY_MATCH_STRING_OPTS(); -#undef M_CP_STROPT -#undef M_CP_STRARRAYOPT - free(newopts); } #define GETPW(b, id) \ @@ -885,22 +850,19 @@ mm_terminate(void) /* Request state information */ void -mm_get_state(struct ssh *ssh, struct include_list *includes, - struct sshbuf *conf, struct sshbuf **confdatap, +mm_get_state(struct ssh *ssh, + ServerOptions *opts, struct sshbuf **confdatap, uint64_t *timing_secretp, struct sshbuf **hostkeysp, struct sshbuf **keystatep, u_char **pw_namep, struct sshbuf **authinfop, struct sshbuf **auth_optsp) { - struct sshbuf *m, *inc; - u_char *cp; - size_t len; + struct sshbuf *m, *config; int r; - struct include_item *item; debug3_f("entering"); - if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL) + if ((m = sshbuf_new()) == NULL || (config = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_STATE, m); @@ -909,12 +871,11 @@ mm_get_state(struct ssh *ssh, struct include_list *includes, mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_STATE, m); - if ((r = sshbuf_get_string(m, &cp, &len)) != 0 || + if ((r = sshbuf_froms(m, &config)) != 0 || (r = sshbuf_get_u64(m, timing_secretp)) != 0 || (r = sshbuf_froms(m, hostkeysp)) != 0 || (r = sshbuf_get_stringb(m, ssh->kex->server_version)) != 0 || - (r = sshbuf_get_stringb(m, ssh->kex->client_version)) != 0 || - (r = sshbuf_get_stringb(m, inc)) != 0) + (r = sshbuf_get_stringb(m, ssh->kex->client_version)) != 0) fatal_fr(r, "parse config"); /* postauth */ @@ -926,24 +887,11 @@ mm_get_state(struct ssh *ssh, struct include_list *includes, (r = sshbuf_froms(m, auth_optsp)) != 0) fatal_fr(r, "parse config postauth"); } + if ((r = deserialise_server_options(config, opts)) != 0) + fatal_fr(r, "deserialise_server_options"); - if (conf != NULL && (r = sshbuf_put(conf, cp, len))) - fatal_fr(r, "sshbuf_put"); - - while (sshbuf_len(inc) != 0) { - item = xcalloc(1, sizeof(*item)); - if ((item->contents = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - if ((r = sshbuf_get_cstring(inc, &item->selector, NULL)) != 0 || - (r = sshbuf_get_cstring(inc, &item->filename, NULL)) != 0 || - (r = sshbuf_get_stringb(inc, item->contents)) != 0) - fatal_fr(r, "parse includes"); - TAILQ_INSERT_TAIL(includes, item, entry); - } - - free(cp); sshbuf_free(m); - sshbuf_free(inc); + sshbuf_free(config); debug3_f("done"); } diff --git a/monitor_wrap.h b/monitor_wrap.h index c2f7f97d9..f43759b21 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.54 2026/03/02 02:40:15 djm Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.55 2026/05/31 11:30:50 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -96,8 +96,8 @@ void mm_session_pty_cleanup2(struct Session *); void mm_send_keystate(struct ssh *, struct monitor*); /* state */ -struct include_list; -void mm_get_state(struct ssh *, struct include_list *, struct sshbuf *, +struct ServerOptions; +void mm_get_state(struct ssh *, struct ServerOptions *, struct sshbuf **, uint64_t *, struct sshbuf **, struct sshbuf **, u_char **, struct sshbuf **, struct sshbuf **); diff --git a/servconf.c b/servconf.c index 668259a20..b378a8aee 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.446 2026/04/02 07:38:14 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.447 2026/05/31 11:30:50 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -63,6 +63,8 @@ #include "digest.h" #include "version.h" +#define SSHD_CONFIG_BLOB_VERSION 1 + #if !defined(SSHD_PAM_SERVICE) # define SSHD_PAM_SERVICE "sshd" #endif @@ -83,136 +85,107 @@ void initialize_server_options(ServerOptions *options) { memset(options, 0, sizeof(*options)); +#define SSHCONF_INT(var, conf, flags, ms, def, cp) options->var = -1; +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) options->var = -1; +#define SSHCONF_STRING(var, conf, flags, cp) options->var = NULL; +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) \ + options->nvar = 0; \ + options->var = NULL; +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) \ + init_##funcsuffix(options) +#define SSHCONF_NONCONF(funcsuffix) \ + init_##funcsuffix(options) +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ - /* Portable-specific options */ - options->use_pam = -1; - options->pam_service_name = NULL; - - /* Standard Options */ - options->num_ports = 0; - options->ports_from_cmdline = 0; - options->queued_listen_addrs = NULL; - options->num_queued_listens = 0; - options->listen_addrs = NULL; - options->num_listen_addrs = 0; - options->address_family = -1; - options->routing_domain = NULL; - options->num_host_key_files = 0; - options->num_host_cert_files = 0; - options->host_key_agent = NULL; - options->pid_file = NULL; - options->login_grace_time = -1; - options->permit_root_login = PERMIT_NOT_SET; - options->ignore_rhosts = -1; - options->ignore_user_known_hosts = -1; - options->print_motd = -1; - options->print_lastlog = -1; - options->x11_forwarding = -1; - options->x11_display_offset = -1; - options->x11_use_localhost = -1; - options->permit_tty = -1; - options->permit_user_rc = -1; - options->xauth_location = NULL; - options->strict_modes = -1; - options->tcp_keep_alive = -1; - options->log_facility = SYSLOG_FACILITY_NOT_SET; - options->log_level = SYSLOG_LEVEL_NOT_SET; - options->num_log_verbose = 0; - options->log_verbose = NULL; - options->hostbased_authentication = -1; - options->hostbased_uses_name_from_packet_only = -1; - options->hostbased_accepted_algos = NULL; - options->hostkeyalgorithms = NULL; - options->pubkey_authentication = -1; - options->pubkey_auth_options = -1; - options->pubkey_accepted_algos = NULL; - options->kerberos_authentication = -1; - options->kerberos_or_local_passwd = -1; - options->kerberos_ticket_cleanup = -1; - options->kerberos_get_afs_token = -1; - options->gss_authentication=-1; - options->gss_cleanup_creds = -1; - options->gss_deleg_creds = -1; - options->gss_strict_acceptor = -1; - options->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->permit_empty_passwd = -1; - options->permit_user_env = -1; - options->permit_user_env_allowlist = NULL; - options->compression = -1; - options->rekey_limit = -1; - options->rekey_interval = -1; - options->allow_tcp_forwarding = -1; - options->allow_streamlocal_forwarding = -1; - options->allow_agent_forwarding = -1; - options->num_allow_users = 0; - options->num_deny_users = 0; - options->num_allow_groups = 0; - options->num_deny_groups = 0; - options->ciphers = NULL; - options->macs = NULL; - options->kex_algorithms = NULL; - options->ca_sign_algorithms = NULL; - options->fwd_opts.gateway_ports = -1; - options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; - options->fwd_opts.streamlocal_bind_unlink = -1; - options->num_subsystems = 0; - options->max_startups_begin = -1; - options->max_startups_rate = -1; - options->max_startups = -1; - options->per_source_max_startups = -1; - options->per_source_masklen_ipv4 = -1; - options->per_source_masklen_ipv6 = -1; - options->per_source_penalty_exempt = NULL; - options->per_source_penalty.enabled = -1; - options->per_source_penalty.max_sources4 = -1; - options->per_source_penalty.max_sources6 = -1; - options->per_source_penalty.overflow_mode = -1; - options->per_source_penalty.overflow_mode6 = -1; - options->per_source_penalty.penalty_crash = -1.0; - options->per_source_penalty.penalty_authfail = -1.0; - options->per_source_penalty.penalty_invaliduser = -1.0; - options->per_source_penalty.penalty_noauth = -1.0; - options->per_source_penalty.penalty_grace = -1.0; - options->per_source_penalty.penalty_refuseconnection = -1.0; - options->per_source_penalty.penalty_max = -1.0; - options->per_source_penalty.penalty_min = -1.0; - options->max_authtries = -1; - options->max_sessions = -1; - options->banner = NULL; - options->use_dns = -1; - options->client_alive_interval = -1; - options->client_alive_count_max = -1; - options->num_authkeys_files = 0; - options->num_accept_env = 0; - options->num_setenv = 0; - options->permit_tun = -1; - options->permitted_opens = NULL; - options->permitted_listens = NULL; - options->adm_forced_command = NULL; - options->chroot_directory = NULL; - options->authorized_keys_command = NULL; - options->authorized_keys_command_user = NULL; - options->revoked_keys_files = NULL; - options->num_revoked_keys_files = 0; - options->sk_provider = NULL; - options->trusted_user_ca_keys = NULL; - options->authorized_principals_file = NULL; - options->authorized_principals_command = NULL; - options->authorized_principals_command_user = NULL; - options->ip_qos_interactive = -1; + /* Using macros for these is a bit overkill but forces consistency */ +#define init_hostkeyfile(options) \ + options->host_key_files = 0; \ + options->num_host_key_files = 0; \ + options->host_key_file_userprovided = NULL; +#define init_ipqos(options) \ + options->ip_qos_interactive = -1; \ options->ip_qos_bulk = -1; - options->version_addendum = NULL; - options->fingerprint_hash = -1; - options->disable_forwarding = -1; - options->expose_userauth_info = -1; - options->required_rsa_size = -1; - options->channel_timeouts = NULL; - options->num_channel_timeouts = 0; - options->unused_connection_timeout = -1; - options->sshd_session_path = NULL; - options->sshd_auth_path = NULL; - options->refuse_connection = -1; +#define init_listenaddress(options) \ + options->queued_listen_addrs = NULL; \ + options->num_queued_listens = 0; \ + options->listen_addrs = NULL; \ + options->num_listen_addrs = 0; +#define init_logfacility(options) \ + options->log_facility = SYSLOG_FACILITY_NOT_SET; +#define init_loglevel(options) \ + options->log_level = SYSLOG_LEVEL_NOT_SET; +#define init_port(options) \ + options->num_ports = 0; \ + options->ports_from_cmdline = 0; +#define init_gatewayports(options) \ + options->fwd_opts.gateway_ports = -1; +#define init_streamlocalbindmask(options) \ + options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; +#define init_streamlocalbindunlink(options) \ + options->fwd_opts.streamlocal_bind_unlink = -1; +#define init_maxstartups(options) \ + options->max_startups_begin = -1; \ + options->max_startups_rate = -1; \ + options->max_startups = -1; +#define init_permituserenv(options) \ + options->permit_user_env = -1; \ + options->permit_user_env_allowlist = NULL; +#define init_persourcenetblocksize(options) \ + options->per_source_masklen_ipv4 = -1; \ + options->per_source_masklen_ipv6 = -1; +#define init_persourcepenalties(options) \ + options->per_source_penalty_exempt = NULL; \ + options->per_source_penalty.enabled = -1; \ + options->per_source_penalty.max_sources4 = -1; \ + options->per_source_penalty.max_sources6 = -1; \ + options->per_source_penalty.overflow_mode = -1; \ + options->per_source_penalty.overflow_mode6 = -1; \ + options->per_source_penalty.penalty_crash = -1.0; \ + options->per_source_penalty.penalty_authfail = -1.0; \ + options->per_source_penalty.penalty_invaliduser = -1.0; \ + options->per_source_penalty.penalty_noauth = -1.0; \ + options->per_source_penalty.penalty_grace = -1.0; \ + options->per_source_penalty.penalty_refuseconnection = -1.0; \ + options->per_source_penalty.penalty_max = -1.0; \ + options->per_source_penalty.penalty_min = -1.0; +#define init_rekeylimit(options) \ + options->rekey_limit = -1; \ + options->rekey_interval = -1; +#define init_subsystem(options) \ + options->num_subsystems = 0; \ + options->subsystem_name = NULL; \ + options->subsystem_command = NULL; \ + options->subsystem_args = NULL; +#define init_timingsecret(options) \ + options->timing_secret = 0; + + SSHD_CONFIG_ENTRIES + +#undef init_hostkeyfile +#undef init_ipqos +#undef init_listenaddress +#undef init_logfacility +#undef init_loglevel +#undef init_port +#undef init_gatewayports +#undef init_streamlocalbindmask +#undef init_streamlocalbindunlink +#undef init_maxstartups +#undef init_permituserenv +#undef init_persourcenetblocksize +#undef init_persourcepenalties +#undef init_rekeylimit +#undef init_subsystem +#undef init_timingsecret +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS } /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ @@ -293,15 +266,34 @@ fill_default_server_options(ServerOptions *options) { u_int i; - /* Portable-specific options */ - if (options->use_pam == -1) - options->use_pam = 0; - if (options->pam_service_name == NULL) - options->pam_service_name = xstrdup(SSHD_PAM_SERVICE); +#define SSHCONF_INT(var, conf, flags, ms, def, cp) \ + if (options->var == -1) \ + options->var = def; +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) \ + if (options->var == -1) \ + options->var = def; +#define SSHCONF_STRING(var, conf, flags, cp) /* done manually */ +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) /* done manually */ +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) /* done manually */ +#define SSHCONF_NONCONF(funcsuffix) /* done manually */ +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ + + /* XXX maybe use macros here too to force consistency? */ + + SSHD_CONFIG_ENTRIES + +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS - /* Standard Options */ if (options->num_host_key_files == 0) { - /* fill default hostkeys for protocols */ + /* fill default hostkeys */ servconf_add_hostkey("[default]", 0, options, _PATH_HOST_RSA_KEY_FILE, 0); #ifdef OPENSSL_HAS_ECC @@ -314,97 +306,26 @@ fill_default_server_options(ServerOptions *options) /* No certificates by default */ if (options->num_ports == 0) options->ports[options->num_ports++] = SSH_DEFAULT_PORT; - if (options->address_family == -1) - options->address_family = AF_UNSPEC; if (options->listen_addrs == NULL) add_listen_addr(options, NULL, NULL, 0); if (options->pid_file == NULL) options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); if (options->moduli_file == NULL) options->moduli_file = xstrdup(_PATH_DH_MODULI); - if (options->login_grace_time == -1) - options->login_grace_time = 120; - if (options->permit_root_login == PERMIT_NOT_SET) - options->permit_root_login = PERMIT_NO_PASSWD; - if (options->ignore_rhosts == -1) - options->ignore_rhosts = 1; - if (options->ignore_user_known_hosts == -1) - options->ignore_user_known_hosts = 0; - if (options->print_motd == -1) - options->print_motd = 1; - if (options->print_lastlog == -1) - options->print_lastlog = 1; - if (options->x11_forwarding == -1) - options->x11_forwarding = 0; - if (options->x11_display_offset == -1) - options->x11_display_offset = 10; - if (options->x11_use_localhost == -1) - options->x11_use_localhost = 1; if (options->xauth_location == NULL) options->xauth_location = xstrdup(_PATH_XAUTH); - if (options->permit_tty == -1) - options->permit_tty = 1; - if (options->permit_user_rc == -1) - options->permit_user_rc = 1; - if (options->strict_modes == -1) - options->strict_modes = 1; - if (options->tcp_keep_alive == -1) - options->tcp_keep_alive = 1; if (options->log_facility == SYSLOG_FACILITY_NOT_SET) options->log_facility = SYSLOG_FACILITY_AUTH; if (options->log_level == SYSLOG_LEVEL_NOT_SET) options->log_level = SYSLOG_LEVEL_INFO; - if (options->hostbased_authentication == -1) - options->hostbased_authentication = 0; - if (options->hostbased_uses_name_from_packet_only == -1) - options->hostbased_uses_name_from_packet_only = 0; - if (options->pubkey_authentication == -1) - options->pubkey_authentication = 1; - if (options->pubkey_auth_options == -1) - options->pubkey_auth_options = 0; - if (options->kerberos_authentication == -1) - options->kerberos_authentication = 0; - if (options->kerberos_or_local_passwd == -1) - options->kerberos_or_local_passwd = 1; - if (options->kerberos_ticket_cleanup == -1) - options->kerberos_ticket_cleanup = 1; - if (options->kerberos_get_afs_token == -1) - options->kerberos_get_afs_token = 0; - if (options->gss_authentication == -1) - options->gss_authentication = 0; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; - if (options->gss_deleg_creds == -1) - options->gss_deleg_creds = 1; - if (options->gss_strict_acceptor == -1) - options->gss_strict_acceptor = 1; - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) - options->kbd_interactive_authentication = 1; - if (options->permit_empty_passwd == -1) - options->permit_empty_passwd = 0; if (options->permit_user_env == -1) { options->permit_user_env = 0; options->permit_user_env_allowlist = NULL; } - if (options->compression == -1) -#ifdef WITH_ZLIB - options->compression = COMP_DELAYED; -#else - options->compression = COMP_NONE; -#endif - if (options->rekey_limit == -1) options->rekey_limit = 0; if (options->rekey_interval == -1) options->rekey_interval = 0; - if (options->allow_tcp_forwarding == -1) - options->allow_tcp_forwarding = FORWARD_ALLOW; - if (options->allow_streamlocal_forwarding == -1) - options->allow_streamlocal_forwarding = FORWARD_ALLOW; - if (options->allow_agent_forwarding == -1) - options->allow_agent_forwarding = 1; if (options->fwd_opts.gateway_ports == -1) options->fwd_opts.gateway_ports = 0; if (options->max_startups == -1) @@ -413,8 +334,6 @@ fill_default_server_options(ServerOptions *options) options->max_startups_rate = 30; /* 30% */ if (options->max_startups_begin == -1) options->max_startups_begin = 10; - if (options->per_source_max_startups == -1) - options->per_source_max_startups = INT_MAX; if (options->per_source_masklen_ipv4 == -1) options->per_source_masklen_ipv4 = 32; if (options->per_source_masklen_ipv6 == -1) @@ -445,16 +364,6 @@ fill_default_server_options(ServerOptions *options) options->per_source_penalty.penalty_min = 15.0; if (options->per_source_penalty.penalty_max < 0.0) options->per_source_penalty.penalty_max = 600.0; - if (options->max_authtries == -1) - options->max_authtries = DEFAULT_AUTH_FAIL_MAX; - if (options->max_sessions == -1) - options->max_sessions = DEFAULT_SESSIONS_MAX; - if (options->use_dns == -1) - options->use_dns = 0; - if (options->client_alive_interval == -1) - options->client_alive_interval = 0; - if (options->client_alive_count_max == -1) - options->client_alive_count_max = 3; if (options->num_authkeys_files == 0) { opt_array_append("[default]", 0, "AuthorizedKeysFiles", &options->authorized_keys_files, @@ -465,8 +374,6 @@ fill_default_server_options(ServerOptions *options) &options->num_authkeys_files, _PATH_SSH_USER_PERMITTED_KEYS2); } - if (options->permit_tun == -1) - options->permit_tun = SSH_TUNMODE_NO; if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_DSCP_EF; if (options->ip_qos_bulk == -1) @@ -477,24 +384,12 @@ fill_default_server_options(ServerOptions *options) options->fwd_opts.streamlocal_bind_mask = 0177; if (options->fwd_opts.streamlocal_bind_unlink == -1) options->fwd_opts.streamlocal_bind_unlink = 0; - if (options->fingerprint_hash == -1) - options->fingerprint_hash = SSH_FP_HASH_DEFAULT; - if (options->disable_forwarding == -1) - options->disable_forwarding = 0; - if (options->expose_userauth_info == -1) - options->expose_userauth_info = 0; if (options->sk_provider == NULL) options->sk_provider = xstrdup("internal"); - if (options->required_rsa_size == -1) - options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; - if (options->unused_connection_timeout == -1) - options->unused_connection_timeout = 0; if (options->sshd_session_path == NULL) options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION); if (options->sshd_auth_path == NULL) options->sshd_auth_path = xstrdup(_PATH_SSHD_AUTH); - if (options->refuse_connection == -1) - options->refuse_connection = 0; assemble_algorithms(options); @@ -540,47 +435,31 @@ fill_default_server_options(ServerOptions *options) #undef CLEAR_ON_NONE_ARRAY } +/* Macros to declare ServerOpCodes enum values */ +#define SSHCONF_INT(var, conf, flags, ms, def, cp) s##conf, +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) s##conf, +#define SSHCONF_STRING(var, conf, flags, cp) s##conf, +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) s##conf, +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) s##conf, +#define SSHCONF_NONCONF(funcsuffix) /* empty */ +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ + /* Keyword tokens. */ typedef enum { sBadOption, /* == unknown option */ - /* Portable-specific options */ - sUsePAM, sPAMServiceName, - /* Standard Options */ - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, - sKerberosGetAFSToken, sPasswordAuthentication, - sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, - sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, - sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, - sPermitUserEnvironment, sAllowTcpForwarding, sCompression, - sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, - sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile, - sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms, - sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, - sBanner, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, - sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, - sPerSourcePenalties, sPerSourcePenaltyExemptList, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds, sGssStrictAcceptor, - sAcceptEnv, sSetEnv, sPermitTunnel, - sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, - sHostCertificate, sInclude, - sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, - sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, - sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum, - sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, - sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, - sStreamLocalBindMask, sStreamLocalBindUnlink, - sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, - sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, - sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout, - sSshdSessionPath, sSshdAuthPath, sRefuseConnection, + SSHD_CONFIG_ENTRIES + sMatch, sInclude, sDeprecated, sIgnore, sUnsupported } ServerOpCodes; +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS #define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */ #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ @@ -588,170 +467,44 @@ typedef enum { #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */ #define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */ +/* Macros to define keywords[] entries */ +#define SSHCONF_KW(conf, flags) { #conf, s##conf, flags }, +#define SSHCONF_INT(var, conf, flags, ms, def, cp) SSHCONF_KW(conf, flags) +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) SSHCONF_KW(conf, flags) +#define SSHCONF_STRING(var, conf, flags, cp) SSHCONF_KW(conf, flags) +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) SSHCONF_KW(conf, flags) +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) SSHCONF_KW(conf, flags) +#define SSHCONF_NONCONF(funcsuffix) /* empty */ +#define SSHCONF_DEPRECATED sDeprecated +#define SSHCONF_IGNORE sIgnore +#define SSHCONF_UNSUPPORTED sUnsupported +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) \ + { #conf, opcode, flags }, +#define SSHCONF_ALIAS(old, conf, flags) \ + { #old, s##conf, flags }, + /* Textual representation of the tokens. */ static struct { const char *name; ServerOpCodes opcode; u_int flags; } keywords[] = { - /* Portable-specific options */ -#ifdef USE_PAM - { "usepam", sUsePAM, SSHCFG_GLOBAL }, - { "pamservicename", sPAMServiceName, SSHCFG_ALL }, -#else - { "usepam", sUnsupported, SSHCFG_GLOBAL }, - { "pamservicename", sUnsupported, SSHCFG_ALL }, -#endif - { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, - /* Standard Options */ - { "port", sPort, SSHCFG_GLOBAL }, - { "hostkey", sHostKeyFile, SSHCFG_GLOBAL }, - { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */ - { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL }, - { "pidfile", sPidFile, SSHCFG_GLOBAL }, - { "modulifile", sModuliFile, SSHCFG_GLOBAL }, - { "serverkeybits", sDeprecated, SSHCFG_GLOBAL }, - { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL }, - { "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL }, - { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL }, - { "syslogfacility", sLogFacility, SSHCFG_GLOBAL }, - { "loglevel", sLogLevel, SSHCFG_ALL }, - { "logverbose", sLogVerbose, SSHCFG_ALL }, - { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL }, - { "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL }, - { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, - { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL }, - { "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, - { "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */ - { "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL }, - { "rsaauthentication", sDeprecated, SSHCFG_ALL }, - { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, - { "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, - { "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */ - { "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL }, - { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ -#ifdef KRB5 - { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, - { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL }, - { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL }, -#ifdef USE_AFS - { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL }, -#else - { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, -#endif -#else - { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, - { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, - { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, - { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, -#endif - { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, - { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -#ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, - { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, -#else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapidelegatecredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, -#endif - { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, - { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, - { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ - { "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ - { "checkmail", sDeprecated, SSHCFG_GLOBAL }, - { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, - { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, - { "printmotd", sPrintMotd, SSHCFG_GLOBAL }, -#ifdef DISABLE_LASTLOG - { "printlastlog", sUnsupported, SSHCFG_GLOBAL }, -#else - { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL }, -#endif - { "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL }, - { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, - { "x11forwarding", sX11Forwarding, SSHCFG_ALL }, - { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, - { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, - { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, - { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, - { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL }, - { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL }, - { "uselogin", sDeprecated, SSHCFG_GLOBAL }, - { "compression", sCompression, SSHCFG_GLOBAL }, - { "rekeylimit", sRekeyLimit, SSHCFG_ALL }, - { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, - { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */ - { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL }, - { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL }, - { "allowusers", sAllowUsers, SSHCFG_ALL }, - { "denyusers", sDenyUsers, SSHCFG_ALL }, - { "allowgroups", sAllowGroups, SSHCFG_ALL }, - { "denygroups", sDenyGroups, SSHCFG_ALL }, - { "ciphers", sCiphers, SSHCFG_GLOBAL }, - { "macs", sMacs, SSHCFG_GLOBAL }, - { "protocol", sIgnore, SSHCFG_GLOBAL }, - { "gatewayports", sGatewayPorts, SSHCFG_ALL }, - { "subsystem", sSubsystem, SSHCFG_ALL }, - { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, - { "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL }, - { "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL }, - { "persourcepenalties", sPerSourcePenalties, SSHCFG_GLOBAL }, - { "persourcepenaltyexemptlist", sPerSourcePenaltyExemptList, SSHCFG_GLOBAL }, - { "maxauthtries", sMaxAuthTries, SSHCFG_ALL }, - { "maxsessions", sMaxSessions, SSHCFG_ALL }, - { "banner", sBanner, SSHCFG_ALL }, - { "usedns", sUseDNS, SSHCFG_GLOBAL }, - { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, - { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, - { "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL }, - { "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL }, - { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, - { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL }, - { "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL}, - { "acceptenv", sAcceptEnv, SSHCFG_ALL }, - { "setenv", sSetEnv, SSHCFG_ALL }, - { "permittunnel", sPermitTunnel, SSHCFG_ALL }, - { "permittty", sPermitTTY, SSHCFG_ALL }, - { "permituserrc", sPermitUserRC, SSHCFG_ALL }, + SSHD_CONFIG_ENTRIES { "match", sMatch, SSHCFG_ALL }, - { "permitopen", sPermitOpen, SSHCFG_ALL }, - { "permitlisten", sPermitListen, SSHCFG_ALL }, - { "forcecommand", sForceCommand, SSHCFG_ALL }, - { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, - { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, - { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, - { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, - { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, - { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, { "include", sInclude, SSHCFG_ALL }, - { "ipqos", sIPQoS, SSHCFG_ALL }, - { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, - { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, - { "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL }, - { "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL }, - { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, - { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, - { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, - { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, - { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, - { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, - { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, - { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, - { "rdomain", sRDomain, SSHCFG_ALL }, - { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, - { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, - { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, - { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, - { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, - { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, - { "sshdauthpath", sSshdAuthPath, SSHCFG_GLOBAL }, - { "refuseconnection", sRefuseConnection, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_DEPRECATED +#undef SSHCONF_IGNORE +#undef SSHCONF_UNSUPPORTED +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS static struct { int val; @@ -1044,12 +797,13 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, full_line, line); } else { debug3("checking match for '%s' user %s%s host %s addr %s " - "laddr %s lport %d on line %d", full_line, + "laddr %s lport %d rdomain %s on line %d", full_line, ci->user ? ci->user : "(null)", ci->user_invalid ? " (invalid)" : "", ci->host ? ci->host : "(null)", ci->address ? ci->address : "(null)", - ci->laddress ? ci->laddress : "(null)", ci->lport, line); + ci->laddress ? ci->laddress : "(null)", ci->lport, + ci->rdomain ? ci->rdomain : "(null)", line); } while ((oattrib = argv_next(acp, avp)) != NULL) { @@ -1389,6 +1143,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, switch (opcode) { /* Portable-specific options */ +#ifdef WITH_PAM case sUsePAM: intptr = &options->use_pam; goto parse_flag; @@ -1402,6 +1157,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, if (*activep && *charptr == NULL) *charptr = xstrdup(arg); break; +#endif /* Standard Options */ case sBadOption: @@ -1499,7 +1255,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, *intptr = value; break; - case sHostKeyFile: + case sHostKey: arg = argv_next(&ac, &av); if (!arg || *arg == '\0') fatal("%s line %d: missing file name.", @@ -1630,6 +1386,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, *intptr = value; break; +#ifdef KRB5 case sKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; @@ -1641,11 +1398,14 @@ process_server_config_line_depth(ServerOptions *options, char *line, case sKerberosTicketCleanup: intptr = &options->kerberos_ticket_cleanup; goto parse_flag; - +#ifdef USE_AFS case sKerberosGetAFSToken: intptr = &options->kerberos_get_afs_token; goto parse_flag; +#endif /* USE_AFS */ +#endif /* KRB5 */ +#ifdef GSSAPI case sGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; @@ -1661,6 +1421,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, case sGssStrictAcceptor: intptr = &options->gss_strict_acceptor; goto parse_flag; +#endif /* GSSAPI */ case sPasswordAuthentication: intptr = &options->password_authentication; @@ -1674,9 +1435,11 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->print_motd; goto parse_flag; +#ifndef DISABLE_LASTLOG case sPrintLastLog: intptr = &options->print_lastlog; goto parse_flag; +#endif case sX11Forwarding: intptr = &options->x11_forwarding; @@ -1717,7 +1480,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->tcp_keep_alive; goto parse_flag; - case sEmptyPasswd: + case sPermitEmptyPasswords: intptr = &options->permit_empty_passwd; goto parse_flag; @@ -1789,7 +1552,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->use_dns; goto parse_flag; - case sLogFacility: + case sSyslogFacility: log_facility_ptr = &options->log_facility; arg = argv_next(&ac, &av); value = log_facility_number(arg); @@ -2854,6 +2617,7 @@ parse_server_match_config(ServerOptions *options, parse_server_config(&mo, "reprocess config", cfg, includes, connectinfo, 0); copy_set_server_options(options, &mo, 0); + free_server_options(&mo); } int @@ -2932,93 +2696,1203 @@ servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src) } } +static int +serialise_s32(struct sshbuf *buf, int v) +{ + uint32_t uv; + int r; + + uv = v < 0 ? (uint32_t)(-(v + 1)) + 1 : (uint32_t)v; + if ((r = sshbuf_put_u8(buf, v < 0)) != 0 || + (r = sshbuf_put_u32(buf, uv)) != 0) + return r; + return 0; +} + +static int +serialise_s64(struct sshbuf *buf, int64_t v) +{ + uint64_t uv; + int r; + + uv = v < 0 ? (uint64_t)(-(v + 1)) + 1 : (uint64_t)v; + if ((r = sshbuf_put_u8(buf, v < 0)) != 0 || + (r = sshbuf_put_u64(buf, uv)) != 0) + return r; + return 0; +} + +static int +serialise_mode(struct sshbuf *buf, mode_t v) +{ + u_int uv; + + if (v == (mode_t)-1) + return serialise_s32(buf, -1); + uv = (u_int)v; + if ((mode_t)uv != v || uv > 0777) + return SSH_ERR_INVALID_FORMAT; + return serialise_s32(buf, (int)uv); +} + +static int +serialise_double(struct sshbuf *buf, double v) +{ + /* + * XXX this is no good for a wire encoding. + * It's fine for passing configurations via RPC, but it would + * be nicer to have an exact binary encoding here. + */ + return sshbuf_put(buf, &v, sizeof(v)); +} + +static int +serialise_nullable_string(struct sshbuf *buf, const char *s) +{ + int r; + + if ((r = sshbuf_put_u8(buf, s != NULL)) != 0) + return r; + if (s == NULL) + return 0; + return sshbuf_put_cstring(buf, s); +} + +static int +serialise_nullable_string_array(struct sshbuf *buf, char **a, u_int n) +{ + int r; + u_int i; + + if ((r = sshbuf_put_u32(buf, n)) != 0) + return r; + for (i = 0; i < n; i++) { + if ((r = serialise_nullable_string(buf, a[i])) != 0) + return r; + } + return 0; +} + +static int +serialise_hostkeyfile(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i; + + if ((r = sshbuf_put_u32(buf, options->num_host_key_files)) != 0) { + error_fr(r, "serialise length"); + return r; + } + for (i = 0; i < options->num_host_key_files; i++) { + if ((r = serialise_s32(buf, + options->host_key_file_userprovided[i])) != 0 || + (r = serialise_nullable_string(buf, + options->host_key_files[i])) != 0) { + error_fr(r, "serialise member"); + return r; + } + } + return 0; +} + +static int +serialise_ipqos(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, options->ip_qos_interactive)) != 0 || + (r = serialise_s32(buf, options->ip_qos_bulk)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_listenaddress(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i; + + /* Note: only serialises queued listen addresses */ + if ((r = sshbuf_put_u32(buf, options->num_queued_listens)) != 0) { + error_fr(r, "serialise length"); + return r; + } + for (i = 0; i < options->num_queued_listens; i++) { + const struct queued_listenaddr *qla = + options->queued_listen_addrs + i; + + if ((r = sshbuf_put_cstring(buf, qla->addr)) != 0 || + (r = serialise_s32(buf, qla->port)) != 0 || + (r = serialise_nullable_string(buf, qla->rdomain)) != 0) { + error_fr(r, "serialise member"); + return r; + } + } + return 0; +} + +static int +serialise_logfacility(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, (int)options->log_facility)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_loglevel(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, (int)options->log_level)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_port(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i; + + if ((r = sshbuf_put_u32(buf, options->num_ports)) != 0) { + error_fr(r, "serialise length"); + return r; + } + for (i = 0; i < options->num_ports; i++) { + if ((r = serialise_s32(buf, options->ports[i])) != 0) { + error_fr(r, "serialise port"); + return r; + } + } + return 0; +} + +static int +serialise_gatewayports(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, options->fwd_opts.gateway_ports)) != 0) { + error_fr(r, "serialise"); + return r; + } + return 0; +} + +static int +serialise_streamlocalbindmask(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_mode(buf, + options->fwd_opts.streamlocal_bind_mask)) != 0) { + error_fr(r, "serialise"); + return r; + } + return 0; +} + +static int +serialise_streamlocalbindunlink(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = sshbuf_put_u8(buf, + (options->fwd_opts.streamlocal_bind_unlink != 0))) != 0) { + error_fr(r, "serialise"); + return r; + } + return 0; +} + +static int +serialise_maxstartups(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, options->max_startups_begin)) != 0 || + (r = serialise_s32(buf, options->max_startups_rate)) != 0 || + (r = serialise_s32(buf, options->max_startups)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_permituserenv(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, options->permit_user_env)) != 0 || + (r = serialise_nullable_string(buf, + options->permit_user_env_allowlist)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_persourcenetblocksize(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s32(buf, options->per_source_masklen_ipv4)) != 0 || + (r = serialise_s32(buf, options->per_source_masklen_ipv6)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_persourcepenalties(const ServerOptions *options, struct sshbuf *buf) +{ + const struct per_source_penalty *psp = &options->per_source_penalty; + int r; + + if ((r = serialise_s32(buf, psp->enabled)) != 0 || + (r = serialise_s32(buf, psp->max_sources4)) != 0 || + (r = serialise_s32(buf, psp->max_sources6)) != 0 || + (r = serialise_s32(buf, psp->overflow_mode)) != 0 || + (r = serialise_s32(buf, psp->overflow_mode6)) != 0 || + (r = serialise_double(buf, psp->penalty_crash)) != 0 || + (r = serialise_double(buf, psp->penalty_grace)) != 0 || + (r = serialise_double(buf, psp->penalty_authfail)) != 0 || + (r = serialise_double(buf, psp->penalty_invaliduser)) != 0 || + (r = serialise_double(buf, psp->penalty_noauth)) != 0 || + (r = serialise_double(buf, psp->penalty_refuseconnection)) != 0 || + (r = serialise_double(buf, psp->penalty_max)) != 0 || + (r = serialise_double(buf, psp->penalty_min)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_rekeylimit(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = serialise_s64(buf, options->rekey_limit)) != 0 || + (r = serialise_s32(buf, options->rekey_interval)) != 0) { + error_fr(r, "serialise"); + return r; + } + + return 0; +} + +static int +serialise_subsystem(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i; + + if ((r = sshbuf_put_u32(buf, options->num_subsystems)) != 0) { + error_fr(r, "serialise length"); + return r; + } + for (i = 0; i < options->num_subsystems; i++) { + if ((r = sshbuf_put_cstring(buf, + options->subsystem_name[i])) != 0 || + (r = sshbuf_put_cstring(buf, + options->subsystem_command[i])) != 0 || + (r = sshbuf_put_cstring(buf, + options->subsystem_args[i])) != 0) { + error_fr(r, "serialise member"); + return r; + } + } + return 0; +} + +static int +serialise_timingsecret(const ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = sshbuf_put_u64(buf, options->timing_secret)) != 0) { + error_fr(r, "serialise"); + return r; + } + return 0; +} + + +int +serialise_server_options(const ServerOptions *options, struct sshbuf **bufp) +{ + struct sshbuf *buf = NULL; + int r = SSH_ERR_INTERNAL_ERROR; + + *bufp = NULL; + + if ((buf = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_put_u32(buf, SSHD_CONFIG_BLOB_VERSION)) != 0) { + error_fr(r, "serialise version"); + goto out; + } + +#define SSHCONF_INT(var, conf, flags, ms, def, cp) \ + if ((r = serialise_s32(buf, options->var)) != 0) { \ + error_fr(r, "serialise %s", #var); \ + goto out; \ + } +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) \ + if ((r = serialise_s32(buf, options->var)) != 0) { \ + error_fr(r, "serialise %s", #var); \ + goto out; \ + } +#define SSHCONF_STRING(var, conf, flags, cp) \ + if ((r = serialise_nullable_string(buf, options->var)) != 0) { \ + error_fr(r, "serialise %s", #var); \ + goto out; \ + } +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) \ + if ((r = serialise_nullable_string_array(buf, options->var, \ + options->nvar)) != 0) { \ + error_fr(r, "serialise %s", #var); \ + goto out; \ + } +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) \ + if ((r = serialise_##funcsuffix(options, buf)) != 0) \ + goto out; +#define SSHCONF_NONCONF(funcsuffix) \ + if ((r = serialise_##funcsuffix(options, buf)) != 0) \ + goto out; +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ + + SSHD_CONFIG_ENTRIES + +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS + + /* success */ + r = 0; + *bufp = buf; + buf = NULL; /* transferred */ + out: + sshbuf_free(buf); + return r; +} + +static int +deserialise_s32(struct sshbuf *buf, int *v) +{ + uint32_t tmp; + int r; + u_char was_signed; + + if ((r = sshbuf_get_u8(buf, &was_signed)) != 0 || + (r = sshbuf_get_u32(buf, &tmp)) != 0) + return r; + if (was_signed > 1) + return SSH_ERR_INVALID_FORMAT; + if (was_signed) { + if (tmp > (uint32_t)INT_MAX + 1) + return SSH_ERR_INVALID_FORMAT; + *v = tmp == (uint32_t)INT_MAX + 1 ? INT_MIN : -(int)tmp; + } else { + if (tmp > INT_MAX) + return SSH_ERR_INVALID_FORMAT; + *v = (int)tmp; + } + return 0; +} + +static int +deserialise_s64(struct sshbuf *buf, int64_t *v) +{ + uint64_t tmp; + int r; + u_char was_signed; + + if ((r = sshbuf_get_u8(buf, &was_signed)) != 0 || + (r = sshbuf_get_u64(buf, &tmp)) != 0) + return r; + if (was_signed > 1) + return SSH_ERR_INVALID_FORMAT; + if (was_signed) { + if (tmp > (uint64_t)INT64_MAX + 1) + return SSH_ERR_INVALID_FORMAT; + *v = tmp == (uint64_t)INT64_MAX + 1 ? + INT64_MIN : -(int64_t)tmp; + } else { + if (tmp > INT64_MAX) + return SSH_ERR_INVALID_FORMAT; + *v = (int64_t)tmp; + } + return 0; +} + +static int +deserialise_mode(struct sshbuf *buf, mode_t *v) +{ + int r, tmp; + + if ((r = deserialise_s32(buf, &tmp)) != 0) + return r; + if (tmp == -1) { + *v = (mode_t)-1; + return 0; + } + if (tmp < 0 || tmp > 0777) + return SSH_ERR_INVALID_FORMAT; + *v = (mode_t)tmp; + return 0; +} + +static int +deserialise_double(struct sshbuf *buf, double *v) +{ + return sshbuf_get(buf, v, sizeof(*v)); +} + +static int +deserialise_nullable_string(struct sshbuf *buf, char **sp) +{ + int r; + u_char present; + + if ((r = sshbuf_get_u8(buf, &present)) != 0) + return r; + if (present == 0) { + *sp = NULL; + return 0; + } + if (present != 1) + return SSH_ERR_INVALID_FORMAT; + return sshbuf_get_cstring(buf, sp, NULL); +} + +static void +free_string_array(char **a, u_int n) +{ + u_int i; + + if (a == NULL) + return; + for (i = 0; i < n; i++) + free(a[i]); + free(a); +} + +static int +deserialise_count(struct sshbuf *buf, u_int *np, const char *what) +{ + int r; + uint32_t n; + + if ((r = sshbuf_get_u32(buf, &n)) != 0) { + error_fr(r, "deserialise %s length", what); + return r; + } + if (n > UINT_MAX) { + error_f("bad number of %s", what); + return SSH_ERR_INVALID_FORMAT; + } + if (n > sshbuf_len(buf)) { + error_f("bad number of %s", what); + return SSH_ERR_INVALID_FORMAT; + } + *np = n; + return 0; +} + +static int +deserialise_nullable_string_array(struct sshbuf *buf, char ***arrayp, + u_int *np) +{ + char **a = NULL; + int r; + u_int i, n; + + *arrayp = NULL; + *np = 0; + if ((r = deserialise_count(buf, &n, "strings")) != 0) + return r; + if (n > 0) + a = xcalloc(n, sizeof(*a)); + for (i = 0; i < n; i++) { + if ((r = deserialise_nullable_string(buf, a + i)) != 0) { + free_string_array(a, i + 1); + return r; + } + } + *arrayp = a; + *np = n; + return 0; +} + +static void +free_queued_listen_addrs(struct queued_listenaddr *qla, u_int n) +{ + u_int i; + + if (qla == NULL) + return; + for (i = 0; i < n; i++) { + free(qla[i].addr); + free(qla[i].rdomain); + } + free(qla); +} + +static int +deserialise_hostkeyfile(ServerOptions *options, struct sshbuf *buf) +{ + int r, *userprovided = NULL; + u_int i, n; + char **files = NULL; + + if ((r = deserialise_count(buf, &n, "host key files")) != 0) + return r; + if (n > 0) { + userprovided = xcalloc(n, sizeof(*userprovided)); + files = xcalloc(n, sizeof(*files)); + } + for (i = 0; i < n; i++) { + if ((r = deserialise_s32(buf, userprovided + i)) != 0 || + (r = deserialise_nullable_string(buf, files + i)) != 0) { + error_fr(r, "deserialise member"); + free_string_array(files, i + 1); + free(userprovided); + return r; + } + } + options->num_host_key_files = n; + options->host_key_file_userprovided = userprovided; + options->host_key_files = files; + return 0; +} + +static int +deserialise_ipqos(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_s32(buf, &options->ip_qos_interactive)) != 0 || + (r = deserialise_s32(buf, &options->ip_qos_bulk)) != 0) { + error_fr(r, "deserialise"); + return r; + } + + return 0; +} + +static int +deserialise_listenaddress(ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i, n; + struct queued_listenaddr *qla = NULL; + + if ((r = deserialise_count(buf, &n, "listen addresses")) != 0) + return r; + if (n > 0) + qla = xcalloc(n, sizeof(*qla)); + for (i = 0; i < n; i++) { + if ((r = sshbuf_get_cstring(buf, &qla[i].addr, NULL)) != 0 || + (r = deserialise_s32(buf, &qla[i].port)) != 0 || + (r = deserialise_nullable_string(buf, + &qla[i].rdomain)) != 0) { + error_fr(r, "deserialise member"); + free_queued_listen_addrs(qla, i + 1); + return r; + } + } + options->num_queued_listens = n; + options->queued_listen_addrs = qla; + return 0; +} + +static int +deserialise_logfacility(ServerOptions *options, struct sshbuf *buf) +{ + int r, tmp; + + if ((r = deserialise_s32(buf, &tmp)) != 0) { + error_fr(r, "deserialise"); + return r; + } + if (tmp != SYSLOG_FACILITY_NOT_SET && + log_facility_name((SyslogFacility)tmp) == NULL) { + error_f("bad syslog facility"); + return SSH_ERR_INVALID_FORMAT; + } + options->log_facility = (SyslogFacility)tmp; + + return 0; +} + +static int +deserialise_loglevel(ServerOptions *options, struct sshbuf *buf) +{ + int r, tmp; + + if ((r = deserialise_s32(buf, &tmp)) != 0) { + error_fr(r, "deserialise"); + return r; + } + if (tmp != SYSLOG_LEVEL_NOT_SET && + log_level_name((LogLevel)tmp) == NULL) { + error_f("bad log level"); + return SSH_ERR_INVALID_FORMAT; + } + options->log_level = (LogLevel)tmp; + + return 0; +} + +static int +deserialise_port(ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i, n; + + if ((r = deserialise_count(buf, &n, "ports")) != 0) + return r; + if (n > MAX_PORTS) { + error_f("bad number of ports"); + return SSH_ERR_INVALID_FORMAT; + } + options->num_ports = n; + memset(options->ports, 0, sizeof(options->ports)); + for (i = 0; i < options->num_ports; i++) { + if ((r = deserialise_s32(buf, options->ports + i)) != 0) { + error_fr(r, "deserialise port"); + return r; + } + } + return 0; +} + +static int +deserialise_gatewayports(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_s32(buf, &options->fwd_opts.gateway_ports)) != 0) { + error_fr(r, "deserialise"); + return r; + } + return 0; +} + +static int +deserialise_streamlocalbindmask(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_mode(buf, + &options->fwd_opts.streamlocal_bind_mask)) != 0) { + error_fr(r, "deserialise"); + return r; + } + return 0; +} + +static int +deserialise_streamlocalbindunlink(ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_char tmp; + + if ((r = sshbuf_get_u8(buf, &tmp)) != 0) { + error_fr(r, "deserialise"); + return r; + } + if (tmp > 1) { + error_f("bad boolean"); + return SSH_ERR_INVALID_FORMAT; + } + options->fwd_opts.streamlocal_bind_unlink = tmp; + return 0; +} + +static int +deserialise_maxstartups(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_s32(buf, &options->max_startups_begin)) != 0 || + (r = deserialise_s32(buf, &options->max_startups_rate)) != 0 || + (r = deserialise_s32(buf, &options->max_startups)) != 0) { + error_fr(r, "deserialise"); + return r; + } + + return 0; +} + +static int +deserialise_permituserenv(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_s32(buf, &options->permit_user_env)) != 0 || + (r = deserialise_nullable_string(buf, + &options->permit_user_env_allowlist)) != 0) { + error_fr(r, "deserialise"); + return r; + } + return 0; +} + +static int +deserialise_persourcenetblocksize(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_s32(buf, + &options->per_source_masklen_ipv4)) != 0 || + (r = deserialise_s32(buf, + &options->per_source_masklen_ipv6)) != 0) { + error_fr(r, "deserialise"); + return r; + } + + return 0; +} + +static int +deserialise_persourcepenalties(ServerOptions *options, struct sshbuf *buf) +{ + struct per_source_penalty *psp = &options->per_source_penalty; + int r; + + if ((r = deserialise_s32(buf, &psp->enabled)) != 0 || + (r = deserialise_s32(buf, &psp->max_sources4)) != 0 || + (r = deserialise_s32(buf, &psp->max_sources6)) != 0 || + (r = deserialise_s32(buf, &psp->overflow_mode)) != 0 || + (r = deserialise_s32(buf, &psp->overflow_mode6)) != 0 || + (r = deserialise_double(buf, &psp->penalty_crash)) != 0 || + (r = deserialise_double(buf, &psp->penalty_grace)) != 0 || + (r = deserialise_double(buf, &psp->penalty_authfail)) != 0 || + (r = deserialise_double(buf, &psp->penalty_invaliduser)) != 0 || + (r = deserialise_double(buf, &psp->penalty_noauth)) != 0 || + (r = deserialise_double(buf, + &psp->penalty_refuseconnection)) != 0 || + (r = deserialise_double(buf, &psp->penalty_max)) != 0 || + (r = deserialise_double(buf, &psp->penalty_min)) != 0) { + error_fr(r, "deserialise"); + return r; + } + + return 0; +} + +static int +deserialise_rekeylimit(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = deserialise_s64(buf, &options->rekey_limit)) != 0 || + (r = deserialise_s32(buf, &options->rekey_interval)) != 0) { + error_fr(r, "deserialise"); + return r; + } + + return 0; +} + +static int +deserialise_subsystem(ServerOptions *options, struct sshbuf *buf) +{ + int r; + u_int i, n; + char **names = NULL, **commands = NULL, **args = NULL; + + if ((r = deserialise_count(buf, &n, "subsystems")) != 0) + return r; + if (n > 0) { + names = xcalloc(n, sizeof(*names)); + commands = xcalloc(n, sizeof(*names)); + args = xcalloc(n, sizeof(*args)); + } + for (i = 0; i < n; i++) { + if ((r = sshbuf_get_cstring(buf, names + i, NULL)) != 0 || + (r = sshbuf_get_cstring(buf, commands + i, NULL)) != 0 || + (r = sshbuf_get_cstring(buf, args + i, NULL)) != 0) { + error_fr(r, "deserialise member"); + free_string_array(names, i + 1); + free_string_array(commands, i + 1); + free_string_array(args, i + 1); + return r; + } + } + options->num_subsystems = n; + options->subsystem_name = names; + options->subsystem_command = commands; + options->subsystem_args = args; + return 0; +} + +static int +deserialise_timingsecret(ServerOptions *options, struct sshbuf *buf) +{ + int r; + + if ((r = sshbuf_get_u64(buf, &options->timing_secret)) != 0) { + error_fr(r, "deserialise"); + return r; + } + return 0; +} + +int +deserialise_server_options(struct sshbuf *buf, ServerOptions *options) +{ + int r = SSH_ERR_INTERNAL_ERROR; + uint32_t version; + ServerOptions new_options; + + initialize_server_options(&new_options); + if ((r = sshbuf_get_u32(buf, &version)) != 0) { + error_fr(r, "deserialise version"); + goto out; + } + if (version != SSHD_CONFIG_BLOB_VERSION) { + error_f("unsupported config blob version %u", version); + r = SSH_ERR_INVALID_FORMAT; + goto out; + } +#define SSHCONF_INT(var, conf, flags, ms, def, cp) \ + if ((r = deserialise_s32(buf, &new_options.var)) != 0) { \ + error_fr(r, "deserialise %s", #var); \ + goto out; \ + } +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) \ + if ((r = deserialise_s32(buf, &new_options.var)) != 0) { \ + error_fr(r, "deserialise %s", #var); \ + goto out; \ + } +#define SSHCONF_STRING(var, conf, flags, cp) \ + if ((r = deserialise_nullable_string(buf, &new_options.var)) != 0) { \ + error_fr(r, "deserialise %s", #var); \ + goto out; \ + } +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) \ + if ((r = deserialise_nullable_string_array(buf, &new_options.var, \ + &new_options.nvar)) != 0) { \ + error_fr(r, "deserialise %s", #var); \ + goto out; \ + } +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) \ + if ((r = deserialise_##funcsuffix(&new_options, buf)) != 0) \ + goto out; +#define SSHCONF_NONCONF(funcsuffix) \ + if ((r = deserialise_##funcsuffix(&new_options, buf)) != 0) \ + goto out; +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ + + SSHD_CONFIG_ENTRIES + + if (sshbuf_len(buf) != 0) { + error_f("trailing data in config blob"); + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS + + /* success */ + r = 0; + free_server_options(options); + *options = new_options; + memset(&new_options, 0, sizeof(new_options)); + out: + free_server_options(&new_options); + return r; +} + +static void +free_hostkeyfile(ServerOptions *options) +{ + u_int i; + + for (i = 0; i < options->num_host_key_files; i++) + free(options->host_key_files[i]); + free(options->host_key_files); + free(options->host_key_file_userprovided); +} + +static void +free_listenaddress(ServerOptions *options) +{ + u_int i; + + free_queued_listen_addrs(options->queued_listen_addrs, + options->num_queued_listens); + + for (i = 0; i < options->num_listen_addrs; i++) { + free(options->listen_addrs[i].rdomain); + if (options->listen_addrs[i].addrs != NULL) + freeaddrinfo(options->listen_addrs[i].addrs); + } + free(options->listen_addrs); +} + +static void +free_permituserenv(ServerOptions *options) +{ + free(options->permit_user_env_allowlist); +} + +static void +free_subsystem(ServerOptions *options) +{ + u_int i; + + for (i = 0; i < options->num_subsystems; i++) { + free(options->subsystem_name[i]); + free(options->subsystem_command[i]); + free(options->subsystem_args[i]); + } + free(options->subsystem_name); + free(options->subsystem_command); + free(options->subsystem_args); +} + +void +free_server_options(ServerOptions *options) +{ +#define SSHCONF_INT(var, conf, flags, ms, def, cp) /* empty */ +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) /* empty */ +#define SSHCONF_STRING(var, conf, flags, cp) free(options->var); +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) \ + free_string_array(options->var, options->nvar); +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) \ + free_##funcsuffix(options); +#define SSHCONF_NONCONF(funcsuffix) \ + free_##funcsuffix(options); +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ + +#define free_ipqos(options) +#define free_logfacility(options) +#define free_loglevel(options) +#define free_port(options) +#define free_gatewayports(options) +#define free_streamlocalbindmask(options) +#define free_streamlocalbindunlink(options) +#define free_maxstartups(options) +#define free_persourcenetblocksize(options) +#define free_persourcepenalties(options) +#define free_rekeylimit(options) +#define free_timingsecret(options) + + SSHD_CONFIG_ENTRIES + +#undef free_ipqos +#undef free_logfacility +#undef free_loglevel +#undef free_port +#undef free_gatewayports +#undef free_streamlocalbindmask +#undef free_streamlocalbindunlink +#undef free_maxstartups +#undef free_persourcenetblocksize +#undef free_persourcepenalties +#undef free_rekeylimit +#undef free_timingsecret + +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS + + initialize_server_options(options); +} + +static void +copy_server_option_int(int *dst, int src) +{ + if (src != -1) + *dst = src; +} + +static void +copy_server_option_int64(int64_t *dst, int64_t src) +{ + if (src != -1) + *dst = src; +} + +static void +copy_server_option_string(char **dst, const char *src) +{ + if (src != NULL && *dst != src) { + free(*dst); + *dst = xstrdup(src); + } +} + +static void +copy_server_option_strarray_values(char ***dst, u_int ndst, + char * const *src, u_int nsrc) +{ + u_int i; + + if (nsrc == 0) + return; + for (i = 0; i < ndst; i++) + free((*dst)[i]); + free(*dst); + *dst = xcalloc(nsrc, sizeof(**dst)); + for (i = 0; i < nsrc; i++) + (*dst)[i] = src[i] == NULL ? NULL : xstrdup(src[i]); +} + +static void +copy_server_option_strarray(char ***dst, u_int *ndst, + char * const *src, u_int nsrc) +{ + if (nsrc == 0) + return; + copy_server_option_strarray_values(dst, *ndst, src, nsrc); + *ndst = nsrc; +} + +static void +copy_ipqos(ServerOptions *dst, const ServerOptions *src) +{ + copy_server_option_int(&dst->ip_qos_interactive, + src->ip_qos_interactive); + copy_server_option_int(&dst->ip_qos_bulk, src->ip_qos_bulk); +} + +static void +copy_gatewayports(ServerOptions *dst, const ServerOptions *src) +{ + copy_server_option_int(&dst->fwd_opts.gateway_ports, + src->fwd_opts.gateway_ports); +} + +static void +copy_streamlocalbindunlink(ServerOptions *dst, const ServerOptions *src) +{ + copy_server_option_int(&dst->fwd_opts.streamlocal_bind_unlink, + src->fwd_opts.streamlocal_bind_unlink); +} + +static void +copy_loglevel(ServerOptions *dst, const ServerOptions *src) +{ + if (src->log_level != -1) + dst->log_level = src->log_level; +} + +static void +copy_rekeylimit(ServerOptions *dst, const ServerOptions *src) +{ + copy_server_option_int64(&dst->rekey_limit, src->rekey_limit); + copy_server_option_int(&dst->rekey_interval, src->rekey_interval); +} + +static void +copy_subsystem(ServerOptions *dst, const ServerOptions *src) +{ + u_int old_num_subsystems = dst->num_subsystems; + + if (src->num_subsystems == 0) + return; + copy_server_option_strarray_values(&dst->subsystem_name, + old_num_subsystems, src->subsystem_name, src->num_subsystems); + copy_server_option_strarray_values(&dst->subsystem_command, + old_num_subsystems, src->subsystem_command, src->num_subsystems); + copy_server_option_strarray_values(&dst->subsystem_args, + old_num_subsystems, src->subsystem_args, src->num_subsystems); + dst->num_subsystems = src->num_subsystems; +} + /* * Copy any supported values that are set. * - * If the preauth flag is set, we do not bother copying the string or - * array values that are not used pre-authentication, because any that we - * do use must be explicitly sent in mm_getpwnamallow(). + * If the preauth flag is set, skip the post-authentication-only manual + * string cleanup and subsystem merge below. */ void copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) { -#define M_CP_INTOPT(n) do {\ - if (src->n != -1) \ - dst->n = src->n; \ -} while (0) + if (dst == src) + return; - M_CP_INTOPT(password_authentication); - M_CP_INTOPT(gss_authentication); - M_CP_INTOPT(pubkey_authentication); - M_CP_INTOPT(pubkey_auth_options); - M_CP_INTOPT(kerberos_authentication); - M_CP_INTOPT(hostbased_authentication); - M_CP_INTOPT(hostbased_uses_name_from_packet_only); - M_CP_INTOPT(kbd_interactive_authentication); - M_CP_INTOPT(permit_root_login); - M_CP_INTOPT(permit_empty_passwd); - M_CP_INTOPT(ignore_rhosts); +#define SSHCONF_INT(var, conf, flags, ms, def, cp) \ + cp(copy_server_option_int(&dst->var, src->var);) +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) \ + cp(copy_server_option_int(&dst->var, src->var);) +#define SSHCONF_STRING(var, conf, flags, cp) \ + cp(copy_server_option_string(&dst->var, src->var);) +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) \ + cp(copy_server_option_strarray(&dst->var, &dst->nvar, \ + src->var, src->nvar);) +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) \ + cp(copy_##funcsuffix(dst, src);) +#define SSHCONF_NONCONF(funcsuffix) /* empty */ +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ - M_CP_INTOPT(allow_tcp_forwarding); - M_CP_INTOPT(allow_streamlocal_forwarding); - M_CP_INTOPT(allow_agent_forwarding); - M_CP_INTOPT(disable_forwarding); - M_CP_INTOPT(expose_userauth_info); - M_CP_INTOPT(permit_tun); - M_CP_INTOPT(fwd_opts.gateway_ports); - M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); - M_CP_INTOPT(x11_display_offset); - M_CP_INTOPT(x11_forwarding); - M_CP_INTOPT(x11_use_localhost); - M_CP_INTOPT(permit_tty); - M_CP_INTOPT(permit_user_rc); - M_CP_INTOPT(max_sessions); - M_CP_INTOPT(max_authtries); - M_CP_INTOPT(client_alive_count_max); - M_CP_INTOPT(client_alive_interval); - M_CP_INTOPT(ip_qos_interactive); - M_CP_INTOPT(ip_qos_bulk); - M_CP_INTOPT(rekey_limit); - M_CP_INTOPT(rekey_interval); - M_CP_INTOPT(log_level); - M_CP_INTOPT(required_rsa_size); - M_CP_INTOPT(unused_connection_timeout); - M_CP_INTOPT(refuse_connection); + SSHD_CONFIG_ENTRIES + +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS /* * The bind_mask is a mode_t that may be unsigned, so we can't use - * M_CP_INTOPT - it does a signed comparison that causes compiler - * warnings. + * copy_server_option_int - it does a signed comparison that causes + * compiler warnings. */ if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) { dst->fwd_opts.streamlocal_bind_mask = src->fwd_opts.streamlocal_bind_mask; } - /* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */ -#define M_CP_STROPT(n) do {\ - if (src->n != NULL && dst->n != src->n) { \ - free(dst->n); \ - dst->n = xstrdup(src->n); \ - } \ -} while(0) -#define M_CP_STRARRAYOPT(s, num_s, clobber) do {\ - u_int i; \ - if (src->num_s != 0) { \ - for (i = 0; i < dst->num_s; i++) \ - free(dst->s[i]); \ - free(dst->s); \ - dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \ - for (i = 0; i < src->num_s; i++) \ - dst->s[i] = xstrdup(src->s[i]); \ - if (clobber) \ - dst->num_s = src->num_s; \ - } \ -} while(0) - - /* See comment in servconf.h */ - COPY_MATCH_STRING_OPTS(); - /* Arguments that accept '+...' need to be expanded */ assemble_algorithms(dst); @@ -3030,12 +3904,14 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) return; /* These options may be "none" to clear a global setting */ - M_CP_STROPT(adm_forced_command); + copy_server_option_string(&dst->adm_forced_command, + src->adm_forced_command); if (option_clear_or_none(dst->adm_forced_command)) { free(dst->adm_forced_command); dst->adm_forced_command = NULL; } - M_CP_STROPT(chroot_directory); + copy_server_option_string(&dst->chroot_directory, + src->chroot_directory); if (option_clear_or_none(dst->chroot_directory)) { free(dst->chroot_directory); dst->chroot_directory = NULL; @@ -3045,10 +3921,6 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) servconf_merge_subsystems(dst, src); } -#undef M_CP_INTOPT -#undef M_CP_STROPT -#undef M_CP_STRARRAYOPT - #define SERVCONF_MAX_DEPTH 16 static void parse_server_config_depth(ServerOptions *options, const char *filename, @@ -3306,7 +4178,7 @@ dump_config(ServerOptions *o) dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc); dump_cfg_fmtint(sStrictModes, o->strict_modes); dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive); - dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd); + dump_cfg_fmtint(sPermitEmptyPasswords, o->permit_empty_passwd); dump_cfg_fmtint(sCompression, o->compression); dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); dump_cfg_fmtint(sUseDNS, o->use_dns); @@ -3353,15 +4225,14 @@ dump_config(ServerOptions *o) /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); - dump_cfg_string(sLogFacility, log_facility_name(o->log_facility)); + dump_cfg_string(sSyslogFacility, log_facility_name(o->log_facility)); /* string array arguments */ dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files, o->authorized_keys_files); dump_cfg_strarray_oneline(sRevokedKeys, o->num_revoked_keys_files, o->revoked_keys_files); - dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, - o->host_key_files); + dump_cfg_strarray(sHostKey, o->num_host_key_files, o->host_key_files); dump_cfg_strarray(sHostCertificate, o->num_host_cert_files, o->host_cert_files); dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); diff --git a/servconf.h b/servconf.h index b06db09e1..a78450343 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.176 2026/03/03 09:57:25 dtucker Exp $ */ +/* $OpenBSD: servconf.h,v 1.177 2026/05/31 11:30:50 djm Exp $ */ /* * Author: Tatu Ylonen @@ -18,6 +18,8 @@ #include +struct sshbuf; + #define MAX_PORTS 256 /* Max # ports. */ /* permit_root_login */ @@ -46,6 +48,15 @@ #define PUBKEYAUTH_TOUCH_REQUIRED (1) #define PUBKEYAUTH_VERIFY_REQUIRED (1<<1) +/* Various defaults */ +#define SSHD_DEFAULT_LOGIN_GRACE_TIME 120 +#define SSHD_DEFAULT_X11_DISPLAY_OFFSET 10 +#ifdef WITH_ZLIB +#define SSHD_DEFAULT_COMPRESSION COMP_DELAYED +#else +#define SSHD_DEFAULT_COMPRESSION COMP_NONE +#endif + struct ssh; /* @@ -83,179 +94,306 @@ struct per_source_penalty { double penalty_min; }; -typedef struct { +/* Options for whether config entries are copied after Match processing */ +#define SSHCFG_COPY_NONE(action) +#define SSHCFG_COPY_MATCH(action) action +#define SSHCFG_COPY_MANUAL(action) + +/* + * This macro is used to generate most of ServerOptions and some of the + * parsing and de/serialisation code in servconf.c. Every variable in + * ServerOptions *must* be represented here. + * + * Variables and configuration options that need special handling (e.g. + * those that represent a struct or use a single option to populate multiple + * values) use the SSHCONF_CUSTOM macro and get manual variable entries in + * ServerOptions below. + * + * Variables that exist in ServerOptions but aren't populated by a keyword + * use the SSHCONF_NONCONF macro and also get manual entries in ServerOptions. + * + * Everything else uses one of the SSHCONF_INT, SSHCONF_INTFLAG, + * SSHCONF_STRING, or SSHCONF_STRARRAY macros. These automatically populate + * their corresponding variable definitions in ServerOptions. The integer + * options also include defaults for initialisation. + * + * Unsupported, deprecated and ignored options use SSHCONF_NOSUPPORT and + * don't populate ServerOptions. Deprecated aliases that still work use + * SSHCONF_ALIAS. + * + * Why go to all this trouble? It ensures a level of consistency between + * the configuration structure and the parsing code and helps us write + * serialisation/deserialisation functions that we can be pretty sure will + * capture every value in the configuration file. + * + * Entry formats: + * SSHCONF_INT(field, keyword, scope, multistate, default, copy) + * SSHCONF_INTFLAG(field, keyword, scope, default, copy) + * SSHCONF_STRING(field, keyword, scope, copy) + * SSHCONF_STRARRAY(field, nfield, keyword, scope, copy) + * SSHCONF_CUSTOM(keyword, suffix, scope, copy) + * SSHCONF_NONCONF(suffix) + * SSHCONF_NOSUPPORT(field, keyword, token, scope) + * SSHCONF_ALIAS(old_keyword, keyword, scope) + */ +#define SSHD_CONFIG_ENTRIES_CUSTOM \ +SSHCONF_CUSTOM(Port, port, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(ListenAddress, listenaddress, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(HostKey, hostkeyfile, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(IPQoS, ipqos, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_CUSTOM(GatewayPorts, gatewayports, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_CUSTOM(StreamLocalBindMask, streamlocalbindmask, SSHCFG_ALL, SSHCFG_COPY_MANUAL) \ +SSHCONF_CUSTOM(StreamLocalBindUnlink, streamlocalbindunlink, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_CUSTOM(SyslogFacility, logfacility, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(LogLevel, loglevel, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_CUSTOM(PermitUserEnvironment, permituserenv, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(Subsystem, subsystem, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_CUSTOM(MaxStartups, maxstartups, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(PerSourceNetBlockSize, persourcenetblocksize, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(PerSourcePenalties, persourcepenalties, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_CUSTOM(RekeyLimit, rekeylimit, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_NONCONF(timingsecret) + +#define SSHD_CONFIG_ENTRIES_MAIN \ +SSHCONF_INT(address_family, AddressFamily, SSHCFG_GLOBAL, multistate_addressfamily, AF_UNSPEC, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(routing_domain, RDomain, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(host_cert_files, num_host_cert_files, HostCertificate, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(host_key_agent, HostKeyAgent, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(pid_file, PidFile, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(moduli_file, ModuliFile, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_INT(login_grace_time, LoginGraceTime, SSHCFG_GLOBAL, NULL, SSHD_DEFAULT_LOGIN_GRACE_TIME, SSHCFG_COPY_NONE) \ +SSHCONF_INT(permit_root_login, PermitRootLogin, SSHCFG_ALL, multistate_permitrootlogin, PERMIT_NO_PASSWD, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(ignore_rhosts, IgnoreRhosts, SSHCFG_ALL, multistate_ignore_rhosts, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(ignore_user_known_hosts, IgnoreUserKnownHosts, SSHCFG_GLOBAL, 0, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(print_motd, PrintMotd, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(x11_forwarding, X11Forwarding, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(x11_display_offset, X11DisplayOffset, SSHCFG_ALL, NULL, SSHD_DEFAULT_X11_DISPLAY_OFFSET, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(x11_use_localhost, X11UseLocalhost, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(xauth_location, XAuthLocation, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(permit_tty, PermitTTY, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(permit_user_rc, PermitUserRC, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(strict_modes, StrictModes, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(tcp_keep_alive, TCPKeepAlive, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(ciphers, Ciphers, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(macs, Macs, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(kex_algorithms, KexAlgorithms, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRARRAY(log_verbose, num_log_verbose, LogVerbose, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(hostbased_authentication, HostbasedAuthentication, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(hostbased_uses_name_from_packet_only, HostbasedUsesNameFromPacketOnly, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(hostbased_accepted_algos, HostbasedAcceptedAlgorithms, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(hostkeyalgorithms, HostKeyAlgorithms, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(ca_sign_algorithms, CASignatureAlgorithms, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(pubkey_auth_options, PubkeyAuthOptions, SSHCFG_ALL, NULL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(pubkey_authentication, PubkeyAuthentication, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(pubkey_accepted_algos, PubkeyAcceptedAlgorithms, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(password_authentication, PasswordAuthentication, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(kbd_interactive_authentication, KbdInteractiveAuthentication, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(permit_empty_passwd, PermitEmptyPasswords, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(compression, Compression, SSHCFG_GLOBAL, multistate_compression, SSHD_DEFAULT_COMPRESSION, SSHCFG_COPY_NONE) \ +SSHCONF_INT(allow_tcp_forwarding, AllowTcpForwarding, SSHCFG_ALL, multistate_tcpfwd, FORWARD_ALLOW, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(allow_streamlocal_forwarding, AllowStreamLocalForwarding, SSHCFG_ALL, multistate_tcpfwd, FORWARD_ALLOW, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(allow_agent_forwarding, AllowAgentForwarding, SSHCFG_ALL, 1, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(disable_forwarding, DisableForwarding, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(allow_users, num_allow_users, AllowUsers, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(deny_users, num_deny_users, DenyUsers, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(allow_groups, num_allow_groups, AllowGroups, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(deny_groups, num_deny_groups, DenyGroups, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(accept_env, num_accept_env, AcceptEnv, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(setenv, num_setenv, SetEnv, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(per_source_max_startups, PerSourceMaxStartups, SSHCFG_GLOBAL, NULL, INT_MAX, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(per_source_penalty_exempt, PerSourcePenaltyExemptList, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_INT(max_authtries, MaxAuthTries, SSHCFG_ALL, NULL, DEFAULT_AUTH_FAIL_MAX, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(max_sessions, MaxSessions, SSHCFG_ALL, NULL, DEFAULT_SESSIONS_MAX, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(banner, Banner, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(use_dns, UseDNS, SSHCFG_GLOBAL, 0, SSHCFG_COPY_NONE) \ +SSHCONF_INT(client_alive_interval, ClientAliveInterval, SSHCFG_ALL, NULL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(client_alive_count_max, ClientAliveCountMax, SSHCFG_ALL, NULL, 3, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(authorized_keys_files, num_authkeys_files, AuthorizedKeysFile, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(adm_forced_command, ForceCommand, SSHCFG_ALL, SSHCFG_COPY_MANUAL) \ +SSHCONF_INTFLAG(permit_tun, PermitTunnel, SSHCFG_ALL, SSH_TUNMODE_NO, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(permitted_opens, num_permitted_opens, PermitOpen, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(permitted_listens, num_permitted_listens, PermitListen, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(chroot_directory, ChrootDirectory, SSHCFG_ALL, SSHCFG_COPY_MANUAL) \ +SSHCONF_STRARRAY(revoked_keys_files, num_revoked_keys_files, RevokedKeys, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(trusted_user_ca_keys, TrustedUserCAKeys, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(authorized_keys_command, AuthorizedKeysCommand, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(authorized_keys_command_user, AuthorizedKeysCommandUser, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(authorized_principals_file, AuthorizedPrincipalsFile, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(authorized_principals_command, AuthorizedPrincipalsCommand, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(authorized_principals_command_user, AuthorizedPrincipalsCommandUser, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(version_addendum, VersionAddendum, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRARRAY(auth_methods, num_auth_methods, AuthenticationMethods, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(fingerprint_hash, FingerprintHash, SSHCFG_GLOBAL, NULL, SSH_FP_HASH_DEFAULT, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(expose_userauth_info, ExposeAuthInfo, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(sk_provider, SecurityKeyProvider, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_INT(required_rsa_size, RequiredRSASize, SSHCFG_ALL, NULL, SSH_RSA_MINIMUM_MODULUS_SIZE, SSHCFG_COPY_MATCH) \ +SSHCONF_STRARRAY(channel_timeouts, num_channel_timeouts, ChannelTimeout, SSHCFG_ALL, SSHCFG_COPY_MATCH) \ +SSHCONF_INT(unused_connection_timeout, UnusedConnectionTimeout, SSHCFG_ALL, NULL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_STRING(sshd_session_path, SshdSessionPath, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_STRING(sshd_auth_path, SshdAuthPath, SSHCFG_GLOBAL, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(refuse_connection, RefuseConnection, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) + +#define SSHD_CONFIG_ENTRIES_LEGACY \ +SSHCONF_NOSUPPORT(server_key_bits, ServerKeyBits, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(key_regeneration_interval, KeyRegenerationInterval, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(rhosts_authentication, RHostsAuthentication, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(rhosts_rsa_authentication, RhostsRSAAuthentication, SSHCONF_DEPRECATED, SSHCFG_ALL) \ +SSHCONF_NOSUPPORT(rsa_authentication, RSAAuthentication, SSHCONF_DEPRECATED, SSHCFG_ALL) \ +SSHCONF_NOSUPPORT(check_mail, CheckMail, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(use_login, UseLogin, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(verify_reverse_mapping, VerifyReverseMapping, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(reverse_mapping_check, ReverseMappingCheck, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(authorized_keys_file2, AuthorizedKeysFile2, SSHCONF_DEPRECATED, SSHCFG_ALL) \ +SSHCONF_NOSUPPORT(use_privilege_separation, UsePrivilegeSeparation, SSHCONF_DEPRECATED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(protocol, Protocol, SSHCONF_IGNORE, SSHCFG_GLOBAL) + +#define SSHD_CONFIG_ENTRIES_ALIASES \ +SSHCONF_ALIAS(HostDSAKey, HostKey, SSHCFG_GLOBAL) \ +SSHCONF_ALIAS(HostBasedAcceptedKeyTypes, HostbasedAcceptedAlgorithms, SSHCFG_ALL) \ +SSHCONF_ALIAS(PubkeyAcceptedKeyTypes, PubkeyAcceptedAlgorithms, SSHCFG_ALL) \ +SSHCONF_ALIAS(DSAAuthentication, PubkeyAuthentication, SSHCFG_GLOBAL) \ +SSHCONF_ALIAS(ChallengeResponseAuthentication, KbdInteractiveAuthentication, SSHCFG_ALL) \ +SSHCONF_ALIAS(SKeyAuthentication, KbdInteractiveAuthentication, SSHCFG_ALL) \ +SSHCONF_ALIAS(KeepAlive, TCPKeepAlive, SSHCFG_GLOBAL) + +#define SSHD_CONFIG_ENTRIES_BASE \ + SSHD_CONFIG_ENTRIES_CUSTOM \ + SSHD_CONFIG_ENTRIES_MAIN \ + SSHD_CONFIG_ENTRIES_LEGACY \ + SSHD_CONFIG_ENTRIES_ALIASES \ + SSHD_CONFIG_ENTRIES_LASTLOG + +#ifdef DISABLE_LASTLOG +#define SSHD_CONFIG_ENTRIES_LASTLOG \ +SSHCONF_NOSUPPORT(print_lastlog, PrintLastLog, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) +#else +#define SSHD_CONFIG_ENTRIES_LASTLOG \ +SSHCONF_INTFLAG(print_lastlog, PrintLastLog, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) +#endif + +/* Compile-time enabled options */ +#ifdef KRB5 + +#ifdef USE_AFS +#define SSHD_CONFIG_KRB5_AFS \ +SSHCONF_INTFLAG(kerberos_get_afs_token, KerberosGetAFSToken, SSHCFG_GLOBAL, 0, SSHCFG_COPY_NONE) +#else /* USE_AFS */ +#define SSHD_CONFIG_KRB5_AFS \ +SSHCONF_NOSUPPORT(kerberos_get_afs_token, KerberosGetAFSToken, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) +#endif /* USE_AFS */ + +#define SSHD_CONFIG_ENTRIES_KRB5 \ +SSHCONF_INTFLAG(kerberos_authentication, KerberosAuthentication, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(kerberos_or_local_passwd, KerberosOrLocalPasswd, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(kerberos_ticket_cleanup, KerberosTicketCleanup, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHD_CONFIG_KRB5_AFS +#else /* KRB5 */ +#define SSHD_CONFIG_ENTRIES_KRB5 \ +SSHCONF_NOSUPPORT(kerberos_authentication, KerberosAuthentication, SSHCONF_UNSUPPORTED, SSHCFG_ALL) \ +SSHCONF_NOSUPPORT(kerberos_or_local_passwd, KerberosOrLocalPasswd, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(kerberos_ticket_cleanup, KerberosTicketCleanup, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(kerberos_get_afs_token, KerberosGetAFSToken, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(kerberos_tgt_passing, KerberosTgtPassing, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(afs_token_passing, AFSTokenPassing, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) +#endif /* KRB5 */ + +#ifdef GSSAPI +#define SSHD_CONFIG_ENTRIES_GSS \ +SSHCONF_INTFLAG(gss_authentication, GssAuthentication, SSHCFG_ALL, 0, SSHCFG_COPY_MATCH) \ +SSHCONF_INTFLAG(gss_cleanup_creds, GssCleanupCreds, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(gss_deleg_creds, GssDelegateCreds, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) \ +SSHCONF_INTFLAG(gss_strict_acceptor, GssStrictAcceptor, SSHCFG_GLOBAL, 1, SSHCFG_COPY_NONE) +#else /* GSSAPI */ +#define SSHD_CONFIG_ENTRIES_GSS \ +SSHCONF_NOSUPPORT(gss_authentication, GssAuthentication, SSHCONF_UNSUPPORTED, SSHCFG_ALL) \ +SSHCONF_NOSUPPORT(gss_cleanup_creds, GssCleanupCreds, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(gss_deleg_creds, GssDelegateCreds, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) \ +SSHCONF_NOSUPPORT(gss_strict_acceptor, GssStrictAcceptor, SSHCONF_UNSUPPORTED, SSHCFG_GLOBAL) +#endif /* GSSAPI */ + +#define SSHD_CONFIG_ENTRIES \ + SSHD_CONFIG_ENTRIES_BASE \ + SSHD_CONFIG_ENTRIES_KRB5 \ + SSHD_CONFIG_ENTRIES_GSS \ + +/* Macros to declare ServerOptions member variables */ +#define SSHCONF_INT(var, conf, flags, ms, def, cp) int var; +#define SSHCONF_INTFLAG(var, conf, flags, def, cp) int var; +#define SSHCONF_STRING(var, conf, flags, cp) char *var; +#define SSHCONF_STRARRAY(var, nvar, conf, flags, cp) \ + char **var; \ + u_int nvar; +#define SSHCONF_CUSTOM(conf, funcsuffix, flags, cp) /* empty */ +#define SSHCONF_NONCONF(funcsuffix) /* empty */ +#define SSHCONF_NOSUPPORT(var, conf, opcode, flags) /* empty */ +#define SSHCONF_ALIAS(old, conf, flags) /* empty */ + +typedef struct ServerOptions { + SSHD_CONFIG_ENTRIES + /* Ports */ u_int num_ports; u_int ports_from_cmdline; int ports[MAX_PORTS]; /* Port number to listen on. */ + /* ListenAddress */ struct queued_listenaddr *queued_listen_addrs; u_int num_queued_listens; struct listenaddr *listen_addrs; u_int num_listen_addrs; - int address_family; /* Address family used by the server. */ - - char *routing_domain; /* Bind session to routing domain */ - + /* HostKey */ char **host_key_files; /* Files containing host keys. */ int *host_key_file_userprovided; /* Key was specified by user. */ u_int num_host_key_files; /* Number of files for host keys. */ - char **host_cert_files; /* Files containing host certs. */ - u_int num_host_cert_files; /* Number of files for host certs. */ - - char *host_key_agent; /* ssh-agent socket for host keys. */ - char *pid_file; /* Where to put our pid */ - char *moduli_file; /* moduli file for DH-GEX */ - int login_grace_time; /* Disconnect if no auth in this time - * (sec). */ - int permit_root_login; /* PERMIT_*, see above */ - int ignore_rhosts; /* Ignore .rhosts and .shosts. */ - int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts - * for RhostsRsaAuth */ - int print_motd; /* If true, print /etc/motd. */ - int print_lastlog; /* If true, print lastlog */ - int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ - int x11_display_offset; /* What DISPLAY number to start - * searching at */ - int x11_use_localhost; /* If true, use localhost for fake X11 server. */ - char *xauth_location; /* Location of xauth program */ - int permit_tty; /* If false, deny pty allocation */ - int permit_user_rc; /* If false, deny ~/.ssh/rc execution */ - int strict_modes; /* If true, require string home dir modes. */ - int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */ + /* IPQoS */ int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ - char *ciphers; /* Supported SSH2 ciphers. */ - char *macs; /* Supported SSH2 macs. */ - char *kex_algorithms; /* SSH2 kex methods in order of preference. */ + /* GatewayPorts, StreamLocalBindMask, StreamLocalBindUnlink */ struct ForwardOptions fwd_opts; /* forwarding options */ + /* LogFacility */ SyslogFacility log_facility; /* Facility for system logging. */ + /* LogLevel */ LogLevel log_level; /* Level for system logging. */ - u_int num_log_verbose; /* Verbose log overrides */ - char **log_verbose; - int hostbased_authentication; /* If true, permit ssh2 hostbased auth */ - int hostbased_uses_name_from_packet_only; /* experimental */ - char *hostbased_accepted_algos; /* Algos allowed for hostbased */ - char *hostkeyalgorithms; /* SSH2 server key types */ - char *ca_sign_algorithms; /* Allowed CA signature algorithms */ - int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ - char *pubkey_accepted_algos; /* Signature algos allowed for pubkey */ - int pubkey_auth_options; /* -1 or mask of PUBKEYAUTH_* flags */ - int kerberos_authentication; /* If true, permit Kerberos - * authentication. */ - int kerberos_or_local_passwd; /* If true, permit kerberos - * and any other password - * authentication mechanism, - * such as SecurID or - * /etc/passwd */ - int kerberos_ticket_cleanup; /* If true, destroy ticket - * file on logout. */ - int kerberos_get_afs_token; /* If true, try to get AFS token if - * authenticated with Kerberos. */ - int gss_authentication; /* If true, permit GSSAPI authentication */ - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ - int gss_deleg_creds; /* If true, accept delegated GSS credentials */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ - int password_authentication; /* If true, permit password - * authentication. */ - int kbd_interactive_authentication; /* If true, permit */ - int permit_empty_passwd; /* If false, do not permit empty - * passwords. */ + /* PermitUserEnvironment */ int permit_user_env; /* If true, read ~/.ssh/environment */ char *permit_user_env_allowlist; /* pattern-list of allowed env names */ - int compression; /* If true, compression is allowed */ - int allow_tcp_forwarding; /* One of FORWARD_* */ - int allow_streamlocal_forwarding; /* One of FORWARD_* */ - int allow_agent_forwarding; - int disable_forwarding; - u_int num_allow_users; - char **allow_users; - u_int num_deny_users; - char **deny_users; - u_int num_allow_groups; - char **allow_groups; - u_int num_deny_groups; - char **deny_groups; - + /* Subsystem */ u_int num_subsystems; char **subsystem_name; char **subsystem_command; char **subsystem_args; - - u_int num_accept_env; - char **accept_env; - u_int num_setenv; - char **setenv; - + /* MaxStartups */ int max_startups_begin; int max_startups_rate; int max_startups; - int per_source_max_startups; + /* PerSourceNetBlockSize */ int per_source_masklen_ipv4; int per_source_masklen_ipv6; - char *per_source_penalty_exempt; + /* PerSourcePenalties */ struct per_source_penalty per_source_penalty; - int max_authtries; - int max_sessions; - char *banner; /* SSH-2 banner message */ - int use_dns; - int client_alive_interval; /* - * poke the client this often to - * see if it's still there - */ - int client_alive_count_max; /* - * If the client is unresponsive - * for this many intervals above, - * disconnect the session - */ - - u_int num_authkeys_files; /* Files containing public keys */ - char **authorized_keys_files; - - char *adm_forced_command; - - int use_pam; /* Enable auth via PAM */ - char *pam_service_name; - - int permit_tun; - - char **permitted_opens; /* May also be one of PERMITOPEN_* */ - u_int num_permitted_opens; - char **permitted_listens; /* May also be one of PERMITOPEN_* */ - u_int num_permitted_listens; - - char *chroot_directory; - uint num_revoked_keys_files; - char **revoked_keys_files; - char *trusted_user_ca_keys; - char *authorized_keys_command; - char *authorized_keys_command_user; - char *authorized_principals_file; - char *authorized_principals_command; - char *authorized_principals_command_user; - + /* RekeyLimit */ int64_t rekey_limit; int rekey_interval; - - char *version_addendum; /* Appended to SSH banner */ - - u_int num_auth_methods; - char **auth_methods; - - int fingerprint_hash; - int expose_userauth_info; + /* Passed by config but not keyword for this */ uint64_t timing_secret; - char *sk_provider; - int required_rsa_size; /* minimum size of RSA keys */ - - char **channel_timeouts; /* inactivity timeout by channel type */ - u_int num_channel_timeouts; - - int unused_connection_timeout; - - char *sshd_session_path; - char *sshd_auth_path; - - int refuse_connection; + /* Placeholders for compile-time disabled things */ + /* XXX djm redo macros to remove these */ +#ifndef WITH_PAM + int use_pam; +#endif +#ifdef DISABLE_LASTLOG + int print_lastlog; +#endif +#ifndef KRB5 + int kerberos_authentication; +#endif } ServerOptions; +#undef SSHCONF_INT +#undef SSHCONF_INTFLAG +#undef SSHCONF_STRING +#undef SSHCONF_STRARRAY +#undef SSHCONF_CUSTOM +#undef SSHCONF_NONCONF +#undef SSHCONF_NOSUPPORT +#undef SSHCONF_ALIAS /* Information about the incoming connection as used by Match */ struct connection_info { @@ -280,49 +418,6 @@ struct include_item { TAILQ_HEAD(include_list, include_item); -/* - * These are string config options that must be copied between the - * Match sub-config and the main config, and must be sent from the - * privsep child to the privsep master. We use a macro to ensure all - * the options are copied and the copies are done in the correct order. - * - * NB. an option must appear in servconf.c:copy_set_server_options() or - * COPY_MATCH_STRING_OPTS here but never both. - */ -#define COPY_MATCH_STRING_OPTS() do { \ - M_CP_STROPT(banner); \ - M_CP_STROPT(trusted_user_ca_keys); \ - M_CP_STROPT(authorized_keys_command); \ - M_CP_STROPT(authorized_keys_command_user); \ - M_CP_STROPT(authorized_principals_file); \ - M_CP_STROPT(authorized_principals_command); \ - M_CP_STROPT(authorized_principals_command_user); \ - M_CP_STROPT(hostbased_accepted_algos); \ - M_CP_STROPT(pubkey_accepted_algos); \ - M_CP_STROPT(ca_sign_algorithms); \ - M_CP_STROPT(routing_domain); \ - M_CP_STROPT(permit_user_env_allowlist); \ - M_CP_STROPT(pam_service_name); \ - M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files, 1);\ - M_CP_STRARRAYOPT(revoked_keys_files, \ - num_revoked_keys_files, 1); \ - M_CP_STRARRAYOPT(allow_users, num_allow_users, 1); \ - M_CP_STRARRAYOPT(deny_users, num_deny_users, 1); \ - M_CP_STRARRAYOPT(allow_groups, num_allow_groups, 1); \ - M_CP_STRARRAYOPT(deny_groups, num_deny_groups, 1); \ - M_CP_STRARRAYOPT(accept_env, num_accept_env, 1); \ - M_CP_STRARRAYOPT(setenv, num_setenv, 1); \ - M_CP_STRARRAYOPT(auth_methods, num_auth_methods, 1); \ - M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens, 1); \ - M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens, 1); \ - M_CP_STRARRAYOPT(channel_timeouts, num_channel_timeouts, 1); \ - M_CP_STRARRAYOPT(log_verbose, num_log_verbose, 1); \ - /* Note: don't clobber num_subsystems until all copied */ \ - M_CP_STRARRAYOPT(subsystem_name, num_subsystems, 0); \ - M_CP_STRARRAYOPT(subsystem_command, num_subsystems, 0); \ - M_CP_STRARRAYOPT(subsystem_args, num_subsystems, 1); \ - } while (0) - void initialize_server_options(ServerOptions *); void fill_default_server_options(ServerOptions *); int process_server_config_line(ServerOptions *, char *, const char *, int, @@ -342,4 +437,8 @@ void servconf_add_hostkey(const char *, const int, void servconf_add_hostcert(const char *, const int, ServerOptions *, const char *path); +int serialise_server_options(const ServerOptions *, struct sshbuf **); +int deserialise_server_options(struct sshbuf *, ServerOptions *); +void free_server_options(ServerOptions *); + #endif /* SERVCONF_H */ diff --git a/sshd-auth.c b/sshd-auth.c index 76350a2a3..ad02aa48c 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.14 2026/03/11 09:10:59 dtucker Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.15 2026/05/31 11:30:50 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -412,14 +412,13 @@ parse_hostkeys(struct sshbuf *hostkeys) } static void -recv_privsep_state(struct ssh *ssh, struct sshbuf *conf, - uint64_t *timing_secretp) +recv_privsep_state(struct ssh *ssh, ServerOptions *o, uint64_t *timing_secretp) { struct sshbuf *hostkeys; debug3_f("begin"); - mm_get_state(ssh, &includes, conf, NULL, timing_secretp, + mm_get_state(ssh, o, NULL, timing_secretp, &hostkeys, NULL, NULL, NULL, NULL); parse_hostkeys(hostkeys); @@ -439,11 +438,9 @@ main(int ac, char **av) extern int optind; int r, opt, have_key = 0; int sock_in = -1, sock_out = -1, rexeced_flag = 0; - char *line; u_int i; mode_t new_umask; Authctxt *authctxt; - struct connection_info *connection_info = NULL; sigset_t sigmask; uint64_t timing_secret = 0; @@ -482,17 +479,16 @@ main(int ac, char **av) "C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) { switch (opt) { case '4': - options.address_family = AF_INET; + /* ignore */ break; case '6': - options.address_family = AF_INET6; + /* ignore */ break; case 'f': - config_file_name = optarg; + /* ignore */ break; case 'c': - servconf_add_hostcert("[command-line]", 0, - &options, optarg); + /* ignore */ break; case 'd': if (debug_flag == 0) { @@ -519,46 +515,28 @@ main(int ac, char **av) /* ignored */ break; case 'q': - options.log_level = SYSLOG_LEVEL_QUIET; + /* ignored */ break; case 'b': /* protocol 1, ignored */ break; case 'p': - options.ports_from_cmdline = 1; - if (options.num_ports >= MAX_PORTS) { - fprintf(stderr, "too many ports.\n"); - exit(1); - } - options.ports[options.num_ports++] = a2port(optarg); - if (options.ports[options.num_ports-1] <= 0) { - fprintf(stderr, "Bad port number.\n"); - exit(1); - } + /* ignored */ break; case 'g': - if ((options.login_grace_time = convtime(optarg)) == -1) { - fprintf(stderr, "Invalid login grace time.\n"); - exit(1); - } + /* ignored */ break; case 'k': /* protocol 1, ignored */ break; case 'h': - servconf_add_hostkey("[command-line]", 0, - &options, optarg, 1); + /* ignored */ break; case 't': case 'T': case 'G': - fatal("test/dump modes not supported"); - break; case 'C': - connection_info = server_get_connection_info(ssh, 0, 0); - if (parse_server_match_testspec(connection_info, - optarg) == -1) - exit(1); + fatal("test/dump modes not supported"); break; case 'u': utmp_len = (u_int)strtonum(optarg, 0, HOST_NAME_MAX+1+1, NULL); @@ -568,11 +546,7 @@ main(int ac, char **av) } break; case 'o': - line = xstrdup(optarg); - if (process_server_config_line(&options, line, - "command-line", 0, NULL, NULL, &includes) != 0) - exit(1); - free(line); + /* ignored */ break; case 'V': fprintf(stderr, "%s, %s\n", @@ -637,10 +611,7 @@ main(int ac, char **av) if ((cfg = sshbuf_new()) == NULL) fatal("sshbuf_new config buf failed"); setproctitle("%s", "[session-auth early]"); - recv_privsep_state(ssh, cfg, &timing_secret); - parse_server_config(&options, "rexec", cfg, &includes, NULL, 1); - /* Fill in default values for those options not explicitly set. */ - fill_default_server_options(&options); + recv_privsep_state(ssh, &options, &timing_secret); options.timing_secret = timing_secret; /* XXX eliminate from unpriv */ ssh_packet_set_qos(ssh, options.ip_qos_interactive, options.ip_qos_bulk);