1*a91a2465SEd Maste /* $OpenBSD: servconf.c,v 1.405 2024/03/04 02:16:11 djm Exp $ */ 2511b41d2SMark Murray /* 3511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4511b41d2SMark Murray * All rights reserved 5511b41d2SMark Murray * 6c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 7c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 8c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 9c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 10c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 11511b41d2SMark Murray */ 12511b41d2SMark Murray 13511b41d2SMark Murray #include "includes.h" 14511b41d2SMark Murray 15333ee039SDag-Erling Smørgrav #include <sys/types.h> 16333ee039SDag-Erling Smørgrav #include <sys/socket.h> 1719261079SEd Maste #include <sys/stat.h> 1819261079SEd Maste #ifdef __OpenBSD__ 1947dd1d1bSDag-Erling Smørgrav #include <sys/sysctl.h> 2047dd1d1bSDag-Erling Smørgrav #endif 21333ee039SDag-Erling Smørgrav 224a421b63SDag-Erling Smørgrav #include <netinet/in.h> 234a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h> 244a421b63SDag-Erling Smørgrav #include <netinet/ip.h> 2547dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_ROUTE_H 2647dd1d1bSDag-Erling Smørgrav #include <net/route.h> 2747dd1d1bSDag-Erling Smørgrav #endif 284a421b63SDag-Erling Smørgrav 29e4a9863fSDag-Erling Smørgrav #include <ctype.h> 30333ee039SDag-Erling Smørgrav #include <netdb.h> 31333ee039SDag-Erling Smørgrav #include <pwd.h> 32333ee039SDag-Erling Smørgrav #include <stdio.h> 33333ee039SDag-Erling Smørgrav #include <stdlib.h> 34333ee039SDag-Erling Smørgrav #include <string.h> 35333ee039SDag-Erling Smørgrav #include <signal.h> 36333ee039SDag-Erling Smørgrav #include <unistd.h> 37bc5531deSDag-Erling Smørgrav #include <limits.h> 38333ee039SDag-Erling Smørgrav #include <stdarg.h> 39d4af9e69SDag-Erling Smørgrav #include <errno.h> 40e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H 41e4a9863fSDag-Erling Smørgrav #include <util.h> 42e4a9863fSDag-Erling Smørgrav #endif 4319261079SEd Maste #ifdef USE_SYSTEM_GLOB 4419261079SEd Maste # include <glob.h> 4519261079SEd Maste #else 4619261079SEd Maste # include "openbsd-compat/glob.h" 4719261079SEd Maste #endif 48333ee039SDag-Erling Smørgrav 49d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 50333ee039SDag-Erling Smørgrav #include "xmalloc.h" 51511b41d2SMark Murray #include "ssh.h" 52ca3176e7SBrian Feldman #include "log.h" 53190cef3dSDag-Erling Smørgrav #include "sshbuf.h" 54a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 55511b41d2SMark Murray #include "servconf.h" 56ca3176e7SBrian Feldman #include "pathnames.h" 57ca3176e7SBrian Feldman #include "cipher.h" 58190cef3dSDag-Erling Smørgrav #include "sshkey.h" 59ca3176e7SBrian Feldman #include "kex.h" 60ca3176e7SBrian Feldman #include "mac.h" 61333ee039SDag-Erling Smørgrav #include "match.h" 62333ee039SDag-Erling Smørgrav #include "channels.h" 63333ee039SDag-Erling Smørgrav #include "groupaccess.h" 64462c32cbSDag-Erling Smørgrav #include "canohost.h" 65462c32cbSDag-Erling Smørgrav #include "packet.h" 66190cef3dSDag-Erling Smørgrav #include "ssherr.h" 676888a9beSDag-Erling Smørgrav #include "hostfile.h" 686888a9beSDag-Erling Smørgrav #include "auth.h" 69bc5531deSDag-Erling Smørgrav #include "myproposal.h" 70bc5531deSDag-Erling Smørgrav #include "digest.h" 71b15c8340SDag-Erling Smørgrav #include "version.h" 72511b41d2SMark Murray 7347dd1d1bSDag-Erling Smørgrav static void add_listen_addr(ServerOptions *, const char *, 7447dd1d1bSDag-Erling Smørgrav const char *, int); 7547dd1d1bSDag-Erling Smørgrav static void add_one_listen_addr(ServerOptions *, const char *, 7647dd1d1bSDag-Erling Smørgrav const char *, int); 7719261079SEd Maste static void parse_server_config_depth(ServerOptions *options, 7819261079SEd Maste const char *filename, struct sshbuf *conf, struct include_list *includes, 7919261079SEd Maste struct connection_info *connectinfo, int flags, int *activep, int depth); 80ca3176e7SBrian Feldman 8180628bacSDag-Erling Smørgrav /* Use of privilege separation or not */ 8280628bacSDag-Erling Smørgrav extern int use_privsep; 83190cef3dSDag-Erling Smørgrav extern struct sshbuf *cfg; 84511b41d2SMark Murray 85511b41d2SMark Murray /* Initializes the server options to their default values. */ 86511b41d2SMark Murray 87511b41d2SMark Murray void 88511b41d2SMark Murray initialize_server_options(ServerOptions *options) 89511b41d2SMark Murray { 90511b41d2SMark Murray memset(options, 0, sizeof(*options)); 91989dd127SDag-Erling Smørgrav 92989dd127SDag-Erling Smørgrav /* Portable-specific options */ 93cf2b5f3bSDag-Erling Smørgrav options->use_pam = -1; 94989dd127SDag-Erling Smørgrav 95989dd127SDag-Erling Smørgrav /* Standard Options */ 96511b41d2SMark Murray options->num_ports = 0; 97511b41d2SMark Murray options->ports_from_cmdline = 0; 98557f75e5SDag-Erling Smørgrav options->queued_listen_addrs = NULL; 99557f75e5SDag-Erling Smørgrav options->num_queued_listens = 0; 100511b41d2SMark Murray options->listen_addrs = NULL; 10147dd1d1bSDag-Erling Smørgrav options->num_listen_addrs = 0; 102aa49c926SDag-Erling Smørgrav options->address_family = -1; 10347dd1d1bSDag-Erling Smørgrav options->routing_domain = NULL; 104ca3176e7SBrian Feldman options->num_host_key_files = 0; 105b15c8340SDag-Erling Smørgrav options->num_host_cert_files = 0; 106e4a9863fSDag-Erling Smørgrav options->host_key_agent = NULL; 107e8aafc91SKris Kennaway options->pid_file = NULL; 108511b41d2SMark Murray options->login_grace_time = -1; 109ca3176e7SBrian Feldman options->permit_root_login = PERMIT_NOT_SET; 110511b41d2SMark Murray options->ignore_rhosts = -1; 111511b41d2SMark Murray options->ignore_user_known_hosts = -1; 112511b41d2SMark Murray options->print_motd = -1; 113ca3176e7SBrian Feldman options->print_lastlog = -1; 114511b41d2SMark Murray options->x11_forwarding = -1; 115511b41d2SMark Murray options->x11_display_offset = -1; 116af12a3e7SDag-Erling Smørgrav options->x11_use_localhost = -1; 117f7167e0eSDag-Erling Smørgrav options->permit_tty = -1; 118a0ee8cc6SDag-Erling Smørgrav options->permit_user_rc = -1; 119c2d3a559SKris Kennaway options->xauth_location = NULL; 120511b41d2SMark Murray options->strict_modes = -1; 1211ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = -1; 122af12a3e7SDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_NOT_SET; 123af12a3e7SDag-Erling Smørgrav options->log_level = SYSLOG_LEVEL_NOT_SET; 12419261079SEd Maste options->num_log_verbose = 0; 12519261079SEd Maste options->log_verbose = NULL; 126ca3176e7SBrian Feldman options->hostbased_authentication = -1; 127ca3176e7SBrian Feldman options->hostbased_uses_name_from_packet_only = -1; 12819261079SEd Maste options->hostbased_accepted_algos = NULL; 129eccfee6eSDag-Erling Smørgrav options->hostkeyalgorithms = NULL; 130ca3176e7SBrian Feldman options->pubkey_authentication = -1; 13119261079SEd Maste options->pubkey_auth_options = -1; 13219261079SEd Maste options->pubkey_accepted_algos = NULL; 133cb96ab36SAssar Westerlund options->kerberos_authentication = -1; 134af12a3e7SDag-Erling Smørgrav options->kerberos_or_local_passwd = -1; 135af12a3e7SDag-Erling Smørgrav options->kerberos_ticket_cleanup = -1; 1361ec0d754SDag-Erling Smørgrav options->kerberos_get_afs_token = -1; 137cf2b5f3bSDag-Erling Smørgrav options->gss_authentication=-1; 138cf2b5f3bSDag-Erling Smørgrav options->gss_cleanup_creds = -1; 139557f75e5SDag-Erling Smørgrav options->gss_strict_acceptor = -1; 140511b41d2SMark Murray options->password_authentication = -1; 14109958426SBrian Feldman options->kbd_interactive_authentication = -1; 142511b41d2SMark Murray options->permit_empty_passwd = -1; 143f388f5efSDag-Erling Smørgrav options->permit_user_env = -1; 14419261079SEd Maste options->permit_user_env_allowlist = NULL; 14580628bacSDag-Erling Smørgrav options->compression = -1; 146e4a9863fSDag-Erling Smørgrav options->rekey_limit = -1; 147e4a9863fSDag-Erling Smørgrav options->rekey_interval = -1; 14809958426SBrian Feldman options->allow_tcp_forwarding = -1; 149a0ee8cc6SDag-Erling Smørgrav options->allow_streamlocal_forwarding = -1; 150d4af9e69SDag-Erling Smørgrav options->allow_agent_forwarding = -1; 151511b41d2SMark Murray options->num_allow_users = 0; 152511b41d2SMark Murray options->num_deny_users = 0; 153511b41d2SMark Murray options->num_allow_groups = 0; 154511b41d2SMark Murray options->num_deny_groups = 0; 155e8aafc91SKris Kennaway options->ciphers = NULL; 156ca3176e7SBrian Feldman options->macs = NULL; 1574a421b63SDag-Erling Smørgrav options->kex_algorithms = NULL; 1582f513db7SEd Maste options->ca_sign_algorithms = NULL; 159a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = -1; 160a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; 161a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = -1; 162c2d3a559SKris Kennaway options->num_subsystems = 0; 163c2d3a559SKris Kennaway options->max_startups_begin = -1; 164c2d3a559SKris Kennaway options->max_startups_rate = -1; 165c2d3a559SKris Kennaway options->max_startups = -1; 16619261079SEd Maste options->per_source_max_startups = -1; 16719261079SEd Maste options->per_source_masklen_ipv4 = -1; 16819261079SEd Maste options->per_source_masklen_ipv6 = -1; 16921e764dfSDag-Erling Smørgrav options->max_authtries = -1; 170d4af9e69SDag-Erling Smørgrav options->max_sessions = -1; 171ca3176e7SBrian Feldman options->banner = NULL; 172cf2b5f3bSDag-Erling Smørgrav options->use_dns = -1; 173ca3176e7SBrian Feldman options->client_alive_interval = -1; 174ca3176e7SBrian Feldman options->client_alive_count_max = -1; 175e146993eSDag-Erling Smørgrav options->num_authkeys_files = 0; 17621e764dfSDag-Erling Smørgrav options->num_accept_env = 0; 177190cef3dSDag-Erling Smørgrav options->num_setenv = 0; 178b74df5b2SDag-Erling Smørgrav options->permit_tun = -1; 1794f52dfbbSDag-Erling Smørgrav options->permitted_opens = NULL; 180190cef3dSDag-Erling Smørgrav options->permitted_listens = NULL; 181333ee039SDag-Erling Smørgrav options->adm_forced_command = NULL; 182d4af9e69SDag-Erling Smørgrav options->chroot_directory = NULL; 1836888a9beSDag-Erling Smørgrav options->authorized_keys_command = NULL; 1846888a9beSDag-Erling Smørgrav options->authorized_keys_command_user = NULL; 185b15c8340SDag-Erling Smørgrav options->revoked_keys_file = NULL; 18619261079SEd Maste options->sk_provider = NULL; 187b15c8340SDag-Erling Smørgrav options->trusted_user_ca_keys = NULL; 188e2f6069cSDag-Erling Smørgrav options->authorized_principals_file = NULL; 189557f75e5SDag-Erling Smørgrav options->authorized_principals_command = NULL; 190557f75e5SDag-Erling Smørgrav options->authorized_principals_command_user = NULL; 1914a421b63SDag-Erling Smørgrav options->ip_qos_interactive = -1; 1924a421b63SDag-Erling Smørgrav options->ip_qos_bulk = -1; 193462c32cbSDag-Erling Smørgrav options->version_addendum = NULL; 194bc5531deSDag-Erling Smørgrav options->fingerprint_hash = -1; 195ca86bcf2SDag-Erling Smørgrav options->disable_forwarding = -1; 1964f52dfbbSDag-Erling Smørgrav options->expose_userauth_info = -1; 19738a52bd3SEd Maste options->required_rsa_size = -1; 198f374ba41SEd Maste options->channel_timeouts = NULL; 199f374ba41SEd Maste options->num_channel_timeouts = 0; 200f374ba41SEd Maste options->unused_connection_timeout = -1; 201b2af61ecSKurt Lidl options->use_blacklist = -1; 202bc5531deSDag-Erling Smørgrav } 203bc5531deSDag-Erling Smørgrav 204bc5531deSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ 205bc5531deSDag-Erling Smørgrav static int 206bc5531deSDag-Erling Smørgrav option_clear_or_none(const char *o) 207bc5531deSDag-Erling Smørgrav { 208bc5531deSDag-Erling Smørgrav return o == NULL || strcasecmp(o, "none") == 0; 209511b41d2SMark Murray } 210511b41d2SMark Murray 211acc1a9efSDag-Erling Smørgrav static void 212acc1a9efSDag-Erling Smørgrav assemble_algorithms(ServerOptions *o) 213acc1a9efSDag-Erling Smørgrav { 2142f513db7SEd Maste char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig; 21519261079SEd Maste char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig; 216190cef3dSDag-Erling Smørgrav int r; 217190cef3dSDag-Erling Smørgrav 218190cef3dSDag-Erling Smørgrav all_cipher = cipher_alg_list(',', 0); 219190cef3dSDag-Erling Smørgrav all_mac = mac_alg_list(','); 220190cef3dSDag-Erling Smørgrav all_kex = kex_alg_list(','); 221190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ','); 2222f513db7SEd Maste all_sig = sshkey_alg_list(0, 1, 1, ','); 22319261079SEd Maste /* remove unsupported algos from default lists */ 22419261079SEd Maste def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher); 22519261079SEd Maste def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac); 22619261079SEd Maste def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex); 22719261079SEd Maste def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); 22819261079SEd Maste def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); 229190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \ 230190cef3dSDag-Erling Smørgrav do { \ 231190cef3dSDag-Erling Smørgrav if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ 23219261079SEd Maste fatal_fr(r, "%s", #what); \ 233190cef3dSDag-Erling Smørgrav } while (0) 23419261079SEd Maste ASSEMBLE(ciphers, def_cipher, all_cipher); 23519261079SEd Maste ASSEMBLE(macs, def_mac, all_mac); 23619261079SEd Maste ASSEMBLE(kex_algorithms, def_kex, all_kex); 23719261079SEd Maste ASSEMBLE(hostkeyalgorithms, def_key, all_key); 23819261079SEd Maste ASSEMBLE(hostbased_accepted_algos, def_key, all_key); 23919261079SEd Maste ASSEMBLE(pubkey_accepted_algos, def_key, all_key); 24019261079SEd Maste ASSEMBLE(ca_sign_algorithms, def_sig, all_sig); 241190cef3dSDag-Erling Smørgrav #undef ASSEMBLE 242190cef3dSDag-Erling Smørgrav free(all_cipher); 243190cef3dSDag-Erling Smørgrav free(all_mac); 244190cef3dSDag-Erling Smørgrav free(all_kex); 245190cef3dSDag-Erling Smørgrav free(all_key); 2462f513db7SEd Maste free(all_sig); 24719261079SEd Maste free(def_cipher); 24819261079SEd Maste free(def_mac); 24919261079SEd Maste free(def_kex); 25019261079SEd Maste free(def_key); 25119261079SEd Maste free(def_sig); 25247dd1d1bSDag-Erling Smørgrav } 25347dd1d1bSDag-Erling Smørgrav 25447dd1d1bSDag-Erling Smørgrav static const char *defaultkey = "[default]"; 25547dd1d1bSDag-Erling Smørgrav 25647dd1d1bSDag-Erling Smørgrav void 25747dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(const char *file, const int line, 25819261079SEd Maste ServerOptions *options, const char *path, int userprovided) 25947dd1d1bSDag-Erling Smørgrav { 26047dd1d1bSDag-Erling Smørgrav char *apath = derelativise_path(path); 26147dd1d1bSDag-Erling Smørgrav 26247dd1d1bSDag-Erling Smørgrav if (file == defaultkey && access(path, R_OK) != 0) 26347dd1d1bSDag-Erling Smørgrav return; 26419261079SEd Maste opt_array_append2(file, line, "HostKey", 26519261079SEd Maste &options->host_key_files, &options->host_key_file_userprovided, 26619261079SEd Maste &options->num_host_key_files, apath, userprovided); 26747dd1d1bSDag-Erling Smørgrav free(apath); 26847dd1d1bSDag-Erling Smørgrav } 26947dd1d1bSDag-Erling Smørgrav 27047dd1d1bSDag-Erling Smørgrav void 27147dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(const char *file, const int line, 27247dd1d1bSDag-Erling Smørgrav ServerOptions *options, const char *path) 27347dd1d1bSDag-Erling Smørgrav { 27447dd1d1bSDag-Erling Smørgrav char *apath = derelativise_path(path); 27547dd1d1bSDag-Erling Smørgrav 27619261079SEd Maste opt_array_append(file, line, "HostCertificate", 27747dd1d1bSDag-Erling Smørgrav &options->host_cert_files, &options->num_host_cert_files, apath); 27847dd1d1bSDag-Erling Smørgrav free(apath); 27947dd1d1bSDag-Erling Smørgrav } 28047dd1d1bSDag-Erling Smørgrav 281511b41d2SMark Murray void 282511b41d2SMark Murray fill_default_server_options(ServerOptions *options) 283511b41d2SMark Murray { 28447dd1d1bSDag-Erling Smørgrav u_int i; 285bc5531deSDag-Erling Smørgrav 286989dd127SDag-Erling Smørgrav /* Portable-specific options */ 287cf2b5f3bSDag-Erling Smørgrav if (options->use_pam == -1) 288f0477b26SDag-Erling Smørgrav options->use_pam = 1; 289989dd127SDag-Erling Smørgrav 290989dd127SDag-Erling Smørgrav /* Standard Options */ 291ca3176e7SBrian Feldman if (options->num_host_key_files == 0) { 292ca3176e7SBrian Feldman /* fill default hostkeys for protocols */ 29347dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options, 29419261079SEd Maste _PATH_HOST_RSA_KEY_FILE, 0); 2954a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 29647dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options, 29719261079SEd Maste _PATH_HOST_ECDSA_KEY_FILE, 0); 2984a421b63SDag-Erling Smørgrav #endif 29947dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options, 30019261079SEd Maste _PATH_HOST_ED25519_KEY_FILE, 0); 30147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS 30247dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options, 30319261079SEd Maste _PATH_HOST_XMSS_KEY_FILE, 0); 30447dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */ 305af12a3e7SDag-Erling Smørgrav } 306144a80bdSDag-Erling Smørgrav if (options->num_host_key_files == 0) 307144a80bdSDag-Erling Smørgrav fatal("No host key files found"); 308b15c8340SDag-Erling Smørgrav /* No certificates by default */ 309511b41d2SMark Murray if (options->num_ports == 0) 310511b41d2SMark Murray options->ports[options->num_ports++] = SSH_DEFAULT_PORT; 311557f75e5SDag-Erling Smørgrav if (options->address_family == -1) 312557f75e5SDag-Erling Smørgrav options->address_family = AF_UNSPEC; 313511b41d2SMark Murray if (options->listen_addrs == NULL) 31447dd1d1bSDag-Erling Smørgrav add_listen_addr(options, NULL, NULL, 0); 315e8aafc91SKris Kennaway if (options->pid_file == NULL) 316bc5531deSDag-Erling Smørgrav options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); 31719261079SEd Maste if (options->moduli_file == NULL) 31819261079SEd Maste options->moduli_file = xstrdup(_PATH_DH_MODULI); 319511b41d2SMark Murray if (options->login_grace_time == -1) 320975616f0SDag-Erling Smørgrav options->login_grace_time = 120; 321ca3176e7SBrian Feldman if (options->permit_root_login == PERMIT_NOT_SET) 322975616f0SDag-Erling Smørgrav options->permit_root_login = PERMIT_NO; 323511b41d2SMark Murray if (options->ignore_rhosts == -1) 324fe5fd017SMark Murray options->ignore_rhosts = 1; 325511b41d2SMark Murray if (options->ignore_user_known_hosts == -1) 326511b41d2SMark Murray options->ignore_user_known_hosts = 0; 327511b41d2SMark Murray if (options->print_motd == -1) 328511b41d2SMark Murray options->print_motd = 1; 329ca3176e7SBrian Feldman if (options->print_lastlog == -1) 330ca3176e7SBrian Feldman options->print_lastlog = 1; 331511b41d2SMark Murray if (options->x11_forwarding == -1) 33277934b7aSEd Maste options->x11_forwarding = 0; 333511b41d2SMark Murray if (options->x11_display_offset == -1) 334fe5fd017SMark Murray options->x11_display_offset = 10; 335af12a3e7SDag-Erling Smørgrav if (options->x11_use_localhost == -1) 336af12a3e7SDag-Erling Smørgrav options->x11_use_localhost = 1; 337c2d3a559SKris Kennaway if (options->xauth_location == NULL) 338bc5531deSDag-Erling Smørgrav options->xauth_location = xstrdup(_PATH_XAUTH); 339f7167e0eSDag-Erling Smørgrav if (options->permit_tty == -1) 340f7167e0eSDag-Erling Smørgrav options->permit_tty = 1; 341a0ee8cc6SDag-Erling Smørgrav if (options->permit_user_rc == -1) 342a0ee8cc6SDag-Erling Smørgrav options->permit_user_rc = 1; 343511b41d2SMark Murray if (options->strict_modes == -1) 344511b41d2SMark Murray options->strict_modes = 1; 3451ec0d754SDag-Erling Smørgrav if (options->tcp_keep_alive == -1) 3461ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = 1; 347af12a3e7SDag-Erling Smørgrav if (options->log_facility == SYSLOG_FACILITY_NOT_SET) 348511b41d2SMark Murray options->log_facility = SYSLOG_FACILITY_AUTH; 349af12a3e7SDag-Erling Smørgrav if (options->log_level == SYSLOG_LEVEL_NOT_SET) 350511b41d2SMark Murray options->log_level = SYSLOG_LEVEL_INFO; 351ca3176e7SBrian Feldman if (options->hostbased_authentication == -1) 352ca3176e7SBrian Feldman options->hostbased_authentication = 0; 353ca3176e7SBrian Feldman if (options->hostbased_uses_name_from_packet_only == -1) 354ca3176e7SBrian Feldman options->hostbased_uses_name_from_packet_only = 0; 355ca3176e7SBrian Feldman if (options->pubkey_authentication == -1) 356ca3176e7SBrian Feldman options->pubkey_authentication = 1; 35719261079SEd Maste if (options->pubkey_auth_options == -1) 35819261079SEd Maste options->pubkey_auth_options = 0; 359989dd127SDag-Erling Smørgrav if (options->kerberos_authentication == -1) 360cf2b5f3bSDag-Erling Smørgrav options->kerberos_authentication = 0; 361af12a3e7SDag-Erling Smørgrav if (options->kerberos_or_local_passwd == -1) 362af12a3e7SDag-Erling Smørgrav options->kerberos_or_local_passwd = 1; 363af12a3e7SDag-Erling Smørgrav if (options->kerberos_ticket_cleanup == -1) 364af12a3e7SDag-Erling Smørgrav options->kerberos_ticket_cleanup = 1; 3651ec0d754SDag-Erling Smørgrav if (options->kerberos_get_afs_token == -1) 3661ec0d754SDag-Erling Smørgrav options->kerberos_get_afs_token = 0; 367cf2b5f3bSDag-Erling Smørgrav if (options->gss_authentication == -1) 368cf2b5f3bSDag-Erling Smørgrav options->gss_authentication = 0; 369cf2b5f3bSDag-Erling Smørgrav if (options->gss_cleanup_creds == -1) 370cf2b5f3bSDag-Erling Smørgrav options->gss_cleanup_creds = 1; 371557f75e5SDag-Erling Smørgrav if (options->gss_strict_acceptor == -1) 372d93a896eSDag-Erling Smørgrav options->gss_strict_acceptor = 1; 373511b41d2SMark Murray if (options->password_authentication == -1) 374b909c84bSDag-Erling Smørgrav options->password_authentication = 0; 37509958426SBrian Feldman if (options->kbd_interactive_authentication == -1) 37619261079SEd Maste options->kbd_interactive_authentication = 1; 377511b41d2SMark Murray if (options->permit_empty_passwd == -1) 378fe5fd017SMark Murray options->permit_empty_passwd = 0; 379190cef3dSDag-Erling Smørgrav if (options->permit_user_env == -1) { 380f388f5efSDag-Erling Smørgrav options->permit_user_env = 0; 38119261079SEd Maste options->permit_user_env_allowlist = NULL; 382190cef3dSDag-Erling Smørgrav } 38380628bacSDag-Erling Smørgrav if (options->compression == -1) 38419261079SEd Maste #ifdef WITH_ZLIB 385d4ecd108SDag-Erling Smørgrav options->compression = COMP_DELAYED; 38619261079SEd Maste #else 38719261079SEd Maste options->compression = COMP_NONE; 38819261079SEd Maste #endif 38919261079SEd Maste 390e4a9863fSDag-Erling Smørgrav if (options->rekey_limit == -1) 391e4a9863fSDag-Erling Smørgrav options->rekey_limit = 0; 392e4a9863fSDag-Erling Smørgrav if (options->rekey_interval == -1) 393e4a9863fSDag-Erling Smørgrav options->rekey_interval = 0; 39409958426SBrian Feldman if (options->allow_tcp_forwarding == -1) 3956888a9beSDag-Erling Smørgrav options->allow_tcp_forwarding = FORWARD_ALLOW; 396a0ee8cc6SDag-Erling Smørgrav if (options->allow_streamlocal_forwarding == -1) 397a0ee8cc6SDag-Erling Smørgrav options->allow_streamlocal_forwarding = FORWARD_ALLOW; 398d4af9e69SDag-Erling Smørgrav if (options->allow_agent_forwarding == -1) 399d4af9e69SDag-Erling Smørgrav options->allow_agent_forwarding = 1; 400a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.gateway_ports == -1) 401a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = 0; 402c2d3a559SKris Kennaway if (options->max_startups == -1) 4036888a9beSDag-Erling Smørgrav options->max_startups = 100; 404c2d3a559SKris Kennaway if (options->max_startups_rate == -1) 4056888a9beSDag-Erling Smørgrav options->max_startups_rate = 30; /* 30% */ 406c2d3a559SKris Kennaway if (options->max_startups_begin == -1) 4076888a9beSDag-Erling Smørgrav options->max_startups_begin = 10; 40819261079SEd Maste if (options->per_source_max_startups == -1) 40919261079SEd Maste options->per_source_max_startups = INT_MAX; 41019261079SEd Maste if (options->per_source_masklen_ipv4 == -1) 41119261079SEd Maste options->per_source_masklen_ipv4 = 32; 41219261079SEd Maste if (options->per_source_masklen_ipv6 == -1) 41319261079SEd Maste options->per_source_masklen_ipv6 = 128; 41421e764dfSDag-Erling Smørgrav if (options->max_authtries == -1) 41521e764dfSDag-Erling Smørgrav options->max_authtries = DEFAULT_AUTH_FAIL_MAX; 416d4af9e69SDag-Erling Smørgrav if (options->max_sessions == -1) 417d4af9e69SDag-Erling Smørgrav options->max_sessions = DEFAULT_SESSIONS_MAX; 418cf2b5f3bSDag-Erling Smørgrav if (options->use_dns == -1) 419c4cd1fa4SDag-Erling Smørgrav options->use_dns = 1; 420ca3176e7SBrian Feldman if (options->client_alive_interval == -1) 421ca3176e7SBrian Feldman options->client_alive_interval = 0; 422ca3176e7SBrian Feldman if (options->client_alive_count_max == -1) 423ca3176e7SBrian Feldman options->client_alive_count_max = 3; 424e146993eSDag-Erling Smørgrav if (options->num_authkeys_files == 0) { 42519261079SEd Maste opt_array_append(defaultkey, 0, "AuthorizedKeysFiles", 42647dd1d1bSDag-Erling Smørgrav &options->authorized_keys_files, 42747dd1d1bSDag-Erling Smørgrav &options->num_authkeys_files, 42847dd1d1bSDag-Erling Smørgrav _PATH_SSH_USER_PERMITTED_KEYS); 42919261079SEd Maste opt_array_append(defaultkey, 0, "AuthorizedKeysFiles", 43047dd1d1bSDag-Erling Smørgrav &options->authorized_keys_files, 43147dd1d1bSDag-Erling Smørgrav &options->num_authkeys_files, 43247dd1d1bSDag-Erling Smørgrav _PATH_SSH_USER_PERMITTED_KEYS2); 433af12a3e7SDag-Erling Smørgrav } 434b74df5b2SDag-Erling Smørgrav if (options->permit_tun == -1) 435b74df5b2SDag-Erling Smørgrav options->permit_tun = SSH_TUNMODE_NO; 4364a421b63SDag-Erling Smørgrav if (options->ip_qos_interactive == -1) 437190cef3dSDag-Erling Smørgrav options->ip_qos_interactive = IPTOS_DSCP_AF21; 4384a421b63SDag-Erling Smørgrav if (options->ip_qos_bulk == -1) 439190cef3dSDag-Erling Smørgrav options->ip_qos_bulk = IPTOS_DSCP_CS1; 440462c32cbSDag-Erling Smørgrav if (options->version_addendum == NULL) 441462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(SSH_VERSION_FREEBSD); 442a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) 443a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = 0177; 444a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_unlink == -1) 445a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = 0; 446bc5531deSDag-Erling Smørgrav if (options->fingerprint_hash == -1) 447bc5531deSDag-Erling Smørgrav options->fingerprint_hash = SSH_FP_HASH_DEFAULT; 448ca86bcf2SDag-Erling Smørgrav if (options->disable_forwarding == -1) 449ca86bcf2SDag-Erling Smørgrav options->disable_forwarding = 0; 4504f52dfbbSDag-Erling Smørgrav if (options->expose_userauth_info == -1) 4514f52dfbbSDag-Erling Smørgrav options->expose_userauth_info = 0; 45219261079SEd Maste if (options->sk_provider == NULL) 45319261079SEd Maste options->sk_provider = xstrdup("internal"); 45438a52bd3SEd Maste if (options->required_rsa_size == -1) 45538a52bd3SEd Maste options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; 456f374ba41SEd Maste if (options->unused_connection_timeout == -1) 457f374ba41SEd Maste options->unused_connection_timeout = 0; 458b2af61ecSKurt Lidl if (options->use_blacklist == -1) 459b2af61ecSKurt Lidl options->use_blacklist = 0; 460eccfee6eSDag-Erling Smørgrav 461acc1a9efSDag-Erling Smørgrav assemble_algorithms(options); 462eccfee6eSDag-Erling Smørgrav 463acc1a9efSDag-Erling Smørgrav /* Turn privilege separation and sandboxing on by default */ 464462c32cbSDag-Erling Smørgrav if (use_privsep == -1) 4652b1970f3SDag-Erling Smørgrav use_privsep = PRIVSEP_ON; 466462c32cbSDag-Erling Smørgrav 467bc5531deSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \ 468bc5531deSDag-Erling Smørgrav do { \ 469bc5531deSDag-Erling Smørgrav if (option_clear_or_none(v)) { \ 470bc5531deSDag-Erling Smørgrav free(v); \ 471bc5531deSDag-Erling Smørgrav v = NULL; \ 472bc5531deSDag-Erling Smørgrav } \ 473bc5531deSDag-Erling Smørgrav } while(0) 474f374ba41SEd Maste #define CLEAR_ON_NONE_ARRAY(v, nv, none) \ 475f374ba41SEd Maste do { \ 476f374ba41SEd Maste if (options->nv == 1 && \ 477f374ba41SEd Maste strcasecmp(options->v[0], none) == 0) { \ 478f374ba41SEd Maste free(options->v[0]); \ 479f374ba41SEd Maste free(options->v); \ 480f374ba41SEd Maste options->v = NULL; \ 481f374ba41SEd Maste options->nv = 0; \ 482f374ba41SEd Maste } \ 483f374ba41SEd Maste } while (0) 484bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->pid_file); 485bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->xauth_location); 486bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->banner); 487bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->trusted_user_ca_keys); 488bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->revoked_keys_file); 48919261079SEd Maste CLEAR_ON_NONE(options->sk_provider); 490557f75e5SDag-Erling Smørgrav CLEAR_ON_NONE(options->authorized_principals_file); 491acc1a9efSDag-Erling Smørgrav CLEAR_ON_NONE(options->adm_forced_command); 492acc1a9efSDag-Erling Smørgrav CLEAR_ON_NONE(options->chroot_directory); 49347dd1d1bSDag-Erling Smørgrav CLEAR_ON_NONE(options->routing_domain); 49419261079SEd Maste CLEAR_ON_NONE(options->host_key_agent); 495f374ba41SEd Maste 496bc5531deSDag-Erling Smørgrav for (i = 0; i < options->num_host_key_files; i++) 497bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->host_key_files[i]); 498bc5531deSDag-Erling Smørgrav for (i = 0; i < options->num_host_cert_files; i++) 499bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->host_cert_files[i]); 500bc5531deSDag-Erling Smørgrav 501f374ba41SEd Maste CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none"); 502f374ba41SEd Maste CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any"); 503f374ba41SEd Maste #undef CLEAR_ON_NONE 504f374ba41SEd Maste #undef CLEAR_ON_NONE_ARRAY 505511b41d2SMark Murray } 506511b41d2SMark Murray 507511b41d2SMark Murray /* Keyword tokens. */ 508511b41d2SMark Murray typedef enum { 509511b41d2SMark Murray sBadOption, /* == unknown option */ 510989dd127SDag-Erling Smørgrav /* Portable-specific options */ 511cf2b5f3bSDag-Erling Smørgrav sUsePAM, 512989dd127SDag-Erling Smørgrav /* Standard Options */ 513ca86bcf2SDag-Erling Smørgrav sPort, sHostKeyFile, sLoginGraceTime, 51419261079SEd Maste sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, 515af12a3e7SDag-Erling Smørgrav sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, 516e9e8876aSEd Maste sKerberosGetAFSToken, sPasswordAuthentication, 517e9e8876aSEd Maste sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, 518ca3176e7SBrian Feldman sPrintMotd, sPrintLastLog, sIgnoreRhosts, 519af12a3e7SDag-Erling Smørgrav sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, 520f7167e0eSDag-Erling Smørgrav sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, 521ca86bcf2SDag-Erling Smørgrav sPermitUserEnvironment, sAllowTcpForwarding, sCompression, 522e4a9863fSDag-Erling Smørgrav sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, 52319261079SEd Maste sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile, 52419261079SEd Maste sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms, 525bc5531deSDag-Erling Smørgrav sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, 526cf2b5f3bSDag-Erling Smørgrav sBanner, sUseDNS, sHostbasedAuthentication, 52719261079SEd Maste sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, 52819261079SEd Maste sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, 529bc5531deSDag-Erling Smørgrav sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, 530557f75e5SDag-Erling Smørgrav sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, 531190cef3dSDag-Erling Smørgrav sAcceptEnv, sSetEnv, sPermitTunnel, 532190cef3dSDag-Erling Smørgrav sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, 533d4af9e69SDag-Erling Smørgrav sUsePrivilegeSeparation, sAllowAgentForwarding, 53419261079SEd Maste sHostCertificate, sInclude, 535e2f6069cSDag-Erling Smørgrav sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, 536557f75e5SDag-Erling Smørgrav sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, 5372f513db7SEd Maste sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum, 5386888a9beSDag-Erling Smørgrav sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, 539a0ee8cc6SDag-Erling Smørgrav sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, 540a0ee8cc6SDag-Erling Smørgrav sStreamLocalBindMask, sStreamLocalBindUnlink, 541ca86bcf2SDag-Erling Smørgrav sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, 54219261079SEd Maste sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, 543f374ba41SEd Maste sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout, 544b2af61ecSKurt Lidl sUseBlacklist, 545ca86bcf2SDag-Erling Smørgrav sDeprecated, sIgnore, sUnsupported 546511b41d2SMark Murray } ServerOpCodes; 547511b41d2SMark Murray 54819261079SEd Maste #define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */ 549333ee039SDag-Erling Smørgrav #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ 550333ee039SDag-Erling Smørgrav #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) 55119261079SEd Maste #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */ 55219261079SEd Maste #define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */ 553333ee039SDag-Erling Smørgrav 554511b41d2SMark Murray /* Textual representation of the tokens. */ 555511b41d2SMark Murray static struct { 556511b41d2SMark Murray const char *name; 557511b41d2SMark Murray ServerOpCodes opcode; 558333ee039SDag-Erling Smørgrav u_int flags; 559511b41d2SMark Murray } keywords[] = { 560989dd127SDag-Erling Smørgrav /* Portable-specific options */ 561cf2b5f3bSDag-Erling Smørgrav #ifdef USE_PAM 562333ee039SDag-Erling Smørgrav { "usepam", sUsePAM, SSHCFG_GLOBAL }, 563cf2b5f3bSDag-Erling Smørgrav #else 564333ee039SDag-Erling Smørgrav { "usepam", sUnsupported, SSHCFG_GLOBAL }, 565975616f0SDag-Erling Smørgrav #endif 566333ee039SDag-Erling Smørgrav { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, 567989dd127SDag-Erling Smørgrav /* Standard Options */ 568333ee039SDag-Erling Smørgrav { "port", sPort, SSHCFG_GLOBAL }, 569333ee039SDag-Erling Smørgrav { "hostkey", sHostKeyFile, SSHCFG_GLOBAL }, 570333ee039SDag-Erling Smørgrav { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */ 571e4a9863fSDag-Erling Smørgrav { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL }, 572333ee039SDag-Erling Smørgrav { "pidfile", sPidFile, SSHCFG_GLOBAL }, 57319261079SEd Maste { "modulifile", sModuliFile, SSHCFG_GLOBAL }, 574ca86bcf2SDag-Erling Smørgrav { "serverkeybits", sDeprecated, SSHCFG_GLOBAL }, 575333ee039SDag-Erling Smørgrav { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL }, 576ca86bcf2SDag-Erling Smørgrav { "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL }, 577d4af9e69SDag-Erling Smørgrav { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL }, 578333ee039SDag-Erling Smørgrav { "syslogfacility", sLogFacility, SSHCFG_GLOBAL }, 5794f52dfbbSDag-Erling Smørgrav { "loglevel", sLogLevel, SSHCFG_ALL }, 58019261079SEd Maste { "logverbose", sLogVerbose, SSHCFG_ALL }, 581333ee039SDag-Erling Smørgrav { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL }, 582ca86bcf2SDag-Erling Smørgrav { "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL }, 583d4af9e69SDag-Erling Smørgrav { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, 584e2f6069cSDag-Erling Smørgrav { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL }, 58519261079SEd Maste { "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, 58619261079SEd Maste { "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */ 587eccfee6eSDag-Erling Smørgrav { "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL }, 588ca86bcf2SDag-Erling Smørgrav { "rsaauthentication", sDeprecated, SSHCFG_ALL }, 589d4af9e69SDag-Erling Smørgrav { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, 59019261079SEd Maste { "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, 59119261079SEd Maste { "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */ 59219261079SEd Maste { "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL }, 593333ee039SDag-Erling Smørgrav { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ 594cf2b5f3bSDag-Erling Smørgrav #ifdef KRB5 595d4af9e69SDag-Erling Smørgrav { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, 596333ee039SDag-Erling Smørgrav { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL }, 597333ee039SDag-Erling Smørgrav { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL }, 5981ec0d754SDag-Erling Smørgrav #ifdef USE_AFS 599333ee039SDag-Erling Smørgrav { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL }, 6001ec0d754SDag-Erling Smørgrav #else 601333ee039SDag-Erling Smørgrav { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, 6021ec0d754SDag-Erling Smørgrav #endif 603cf2b5f3bSDag-Erling Smørgrav #else 604d4af9e69SDag-Erling Smørgrav { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, 605333ee039SDag-Erling Smørgrav { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, 606333ee039SDag-Erling Smørgrav { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, 607333ee039SDag-Erling Smørgrav { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, 608cb96ab36SAssar Westerlund #endif 609333ee039SDag-Erling Smørgrav { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, 610333ee039SDag-Erling Smørgrav { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, 611cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 612d4af9e69SDag-Erling Smørgrav { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 613333ee039SDag-Erling Smørgrav { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 614557f75e5SDag-Erling Smørgrav { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, 615cf2b5f3bSDag-Erling Smørgrav #else 616d4af9e69SDag-Erling Smørgrav { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 617333ee039SDag-Erling Smørgrav { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 618557f75e5SDag-Erling Smørgrav { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, 619511b41d2SMark Murray #endif 620d4af9e69SDag-Erling Smørgrav { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 621d4af9e69SDag-Erling Smørgrav { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 62219261079SEd Maste { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ 62319261079SEd Maste { "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ 624333ee039SDag-Erling Smørgrav { "checkmail", sDeprecated, SSHCFG_GLOBAL }, 625333ee039SDag-Erling Smørgrav { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, 626333ee039SDag-Erling Smørgrav { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, 627333ee039SDag-Erling Smørgrav { "printmotd", sPrintMotd, SSHCFG_GLOBAL }, 628acc1a9efSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG 629acc1a9efSDag-Erling Smørgrav { "printlastlog", sUnsupported, SSHCFG_GLOBAL }, 630acc1a9efSDag-Erling Smørgrav #else 631333ee039SDag-Erling Smørgrav { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL }, 632acc1a9efSDag-Erling Smørgrav #endif 63319261079SEd Maste { "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL }, 634333ee039SDag-Erling Smørgrav { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, 635333ee039SDag-Erling Smørgrav { "x11forwarding", sX11Forwarding, SSHCFG_ALL }, 636333ee039SDag-Erling Smørgrav { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, 637333ee039SDag-Erling Smørgrav { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, 638333ee039SDag-Erling Smørgrav { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, 639333ee039SDag-Erling Smørgrav { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, 640cce7d346SDag-Erling Smørgrav { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL }, 641333ee039SDag-Erling Smørgrav { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL }, 642ca86bcf2SDag-Erling Smørgrav { "uselogin", sDeprecated, SSHCFG_GLOBAL }, 643333ee039SDag-Erling Smørgrav { "compression", sCompression, SSHCFG_GLOBAL }, 644e4a9863fSDag-Erling Smørgrav { "rekeylimit", sRekeyLimit, SSHCFG_ALL }, 645333ee039SDag-Erling Smørgrav { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, 646333ee039SDag-Erling Smørgrav { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */ 647333ee039SDag-Erling Smørgrav { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL }, 648d4af9e69SDag-Erling Smørgrav { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL }, 649462c32cbSDag-Erling Smørgrav { "allowusers", sAllowUsers, SSHCFG_ALL }, 650462c32cbSDag-Erling Smørgrav { "denyusers", sDenyUsers, SSHCFG_ALL }, 651462c32cbSDag-Erling Smørgrav { "allowgroups", sAllowGroups, SSHCFG_ALL }, 652462c32cbSDag-Erling Smørgrav { "denygroups", sDenyGroups, SSHCFG_ALL }, 653333ee039SDag-Erling Smørgrav { "ciphers", sCiphers, SSHCFG_GLOBAL }, 654333ee039SDag-Erling Smørgrav { "macs", sMacs, SSHCFG_GLOBAL }, 655ca86bcf2SDag-Erling Smørgrav { "protocol", sIgnore, SSHCFG_GLOBAL }, 656333ee039SDag-Erling Smørgrav { "gatewayports", sGatewayPorts, SSHCFG_ALL }, 657edf85781SEd Maste { "subsystem", sSubsystem, SSHCFG_ALL }, 658333ee039SDag-Erling Smørgrav { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, 65919261079SEd Maste { "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL }, 66019261079SEd Maste { "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL }, 661d4af9e69SDag-Erling Smørgrav { "maxauthtries", sMaxAuthTries, SSHCFG_ALL }, 662d4af9e69SDag-Erling Smørgrav { "maxsessions", sMaxSessions, SSHCFG_ALL }, 663d4af9e69SDag-Erling Smørgrav { "banner", sBanner, SSHCFG_ALL }, 664333ee039SDag-Erling Smørgrav { "usedns", sUseDNS, SSHCFG_GLOBAL }, 665333ee039SDag-Erling Smørgrav { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, 666333ee039SDag-Erling Smørgrav { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, 667ca86bcf2SDag-Erling Smørgrav { "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL }, 668ca86bcf2SDag-Erling Smørgrav { "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL }, 669e2f6069cSDag-Erling Smørgrav { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, 670e146993eSDag-Erling Smørgrav { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL }, 671d93a896eSDag-Erling Smørgrav { "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL}, 672462c32cbSDag-Erling Smørgrav { "acceptenv", sAcceptEnv, SSHCFG_ALL }, 673190cef3dSDag-Erling Smørgrav { "setenv", sSetEnv, SSHCFG_ALL }, 674e2f6069cSDag-Erling Smørgrav { "permittunnel", sPermitTunnel, SSHCFG_ALL }, 675f7167e0eSDag-Erling Smørgrav { "permittty", sPermitTTY, SSHCFG_ALL }, 676a0ee8cc6SDag-Erling Smørgrav { "permituserrc", sPermitUserRC, SSHCFG_ALL }, 677333ee039SDag-Erling Smørgrav { "match", sMatch, SSHCFG_ALL }, 678333ee039SDag-Erling Smørgrav { "permitopen", sPermitOpen, SSHCFG_ALL }, 679190cef3dSDag-Erling Smørgrav { "permitlisten", sPermitListen, SSHCFG_ALL }, 680333ee039SDag-Erling Smørgrav { "forcecommand", sForceCommand, SSHCFG_ALL }, 681d4af9e69SDag-Erling Smørgrav { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, 682b15c8340SDag-Erling Smørgrav { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, 683b15c8340SDag-Erling Smørgrav { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, 684b15c8340SDag-Erling Smørgrav { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, 685e2f6069cSDag-Erling Smørgrav { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, 6864a421b63SDag-Erling Smørgrav { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, 68719261079SEd Maste { "include", sInclude, SSHCFG_ALL }, 6884a421b63SDag-Erling Smørgrav { "ipqos", sIPQoS, SSHCFG_ALL }, 6896888a9beSDag-Erling Smørgrav { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, 6906888a9beSDag-Erling Smørgrav { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, 691557f75e5SDag-Erling Smørgrav { "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL }, 692557f75e5SDag-Erling Smørgrav { "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL }, 693462c32cbSDag-Erling Smørgrav { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, 6946888a9beSDag-Erling Smørgrav { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, 695a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, 696a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, 697a0ee8cc6SDag-Erling Smørgrav { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, 698bc5531deSDag-Erling Smørgrav { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, 699ca86bcf2SDag-Erling Smørgrav { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, 7004f52dfbbSDag-Erling Smørgrav { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, 70147dd1d1bSDag-Erling Smørgrav { "rdomain", sRDomain, SSHCFG_ALL }, 7022f513db7SEd Maste { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, 70319261079SEd Maste { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, 70438a52bd3SEd Maste { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, 705f374ba41SEd Maste { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, 706f374ba41SEd Maste { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, 707b2af61ecSKurt Lidl { "useblacklist", sUseBlacklist, SSHCFG_GLOBAL }, 708e426c743SEd Maste { "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */ 709a93cbba2SEd Maste 710333ee039SDag-Erling Smørgrav { NULL, sBadOption, 0 } 711511b41d2SMark Murray }; 712511b41d2SMark Murray 713d4af9e69SDag-Erling Smørgrav static struct { 714d4af9e69SDag-Erling Smørgrav int val; 715d4af9e69SDag-Erling Smørgrav char *text; 716d4af9e69SDag-Erling Smørgrav } tunmode_desc[] = { 717d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_NO, "no" }, 718d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_POINTOPOINT, "point-to-point" }, 719d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_ETHERNET, "ethernet" }, 720d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_YES, "yes" }, 721d4af9e69SDag-Erling Smørgrav { -1, NULL } 722d4af9e69SDag-Erling Smørgrav }; 723d4af9e69SDag-Erling Smørgrav 724190cef3dSDag-Erling Smørgrav /* Returns an opcode name from its number */ 725190cef3dSDag-Erling Smørgrav 726190cef3dSDag-Erling Smørgrav static const char * 727190cef3dSDag-Erling Smørgrav lookup_opcode_name(ServerOpCodes code) 728190cef3dSDag-Erling Smørgrav { 729190cef3dSDag-Erling Smørgrav u_int i; 730190cef3dSDag-Erling Smørgrav 731190cef3dSDag-Erling Smørgrav for (i = 0; keywords[i].name != NULL; i++) 732190cef3dSDag-Erling Smørgrav if (keywords[i].opcode == code) 733190cef3dSDag-Erling Smørgrav return(keywords[i].name); 734190cef3dSDag-Erling Smørgrav return "UNKNOWN"; 735190cef3dSDag-Erling Smørgrav } 736190cef3dSDag-Erling Smørgrav 737190cef3dSDag-Erling Smørgrav 738511b41d2SMark Murray /* 739ca3176e7SBrian Feldman * Returns the number of the token pointed to by cp or sBadOption. 740511b41d2SMark Murray */ 741511b41d2SMark Murray 742511b41d2SMark Murray static ServerOpCodes 743511b41d2SMark Murray parse_token(const char *cp, const char *filename, 744333ee039SDag-Erling Smørgrav int linenum, u_int *flags) 745511b41d2SMark Murray { 746ca3176e7SBrian Feldman u_int i; 747511b41d2SMark Murray 748511b41d2SMark Murray for (i = 0; keywords[i].name; i++) 749333ee039SDag-Erling Smørgrav if (strcasecmp(cp, keywords[i].name) == 0) { 750333ee039SDag-Erling Smørgrav *flags = keywords[i].flags; 751511b41d2SMark Murray return keywords[i].opcode; 752333ee039SDag-Erling Smørgrav } 753511b41d2SMark Murray 754ca3176e7SBrian Feldman error("%s: line %d: Bad configuration option: %s", 755511b41d2SMark Murray filename, linenum, cp); 756511b41d2SMark Murray return sBadOption; 757511b41d2SMark Murray } 758511b41d2SMark Murray 759b15c8340SDag-Erling Smørgrav char * 760b15c8340SDag-Erling Smørgrav derelativise_path(const char *path) 761b15c8340SDag-Erling Smørgrav { 762bc5531deSDag-Erling Smørgrav char *expanded, *ret, cwd[PATH_MAX]; 763b15c8340SDag-Erling Smørgrav 764bc5531deSDag-Erling Smørgrav if (strcasecmp(path, "none") == 0) 765bc5531deSDag-Erling Smørgrav return xstrdup("none"); 766b15c8340SDag-Erling Smørgrav expanded = tilde_expand_filename(path, getuid()); 76719261079SEd Maste if (path_absolute(expanded)) 768b15c8340SDag-Erling Smørgrav return expanded; 7698ad9b54aSDag-Erling Smørgrav if (getcwd(cwd, sizeof(cwd)) == NULL) 77019261079SEd Maste fatal_f("getcwd: %s", strerror(errno)); 771b15c8340SDag-Erling Smørgrav xasprintf(&ret, "%s/%s", cwd, expanded); 772e4a9863fSDag-Erling Smørgrav free(expanded); 773b15c8340SDag-Erling Smørgrav return ret; 774b15c8340SDag-Erling Smørgrav } 775b15c8340SDag-Erling Smørgrav 776af12a3e7SDag-Erling Smørgrav static void 77747dd1d1bSDag-Erling Smørgrav add_listen_addr(ServerOptions *options, const char *addr, 77847dd1d1bSDag-Erling Smørgrav const char *rdomain, int port) 779511b41d2SMark Murray { 780d4ecd108SDag-Erling Smørgrav u_int i; 781511b41d2SMark Murray 78247dd1d1bSDag-Erling Smørgrav if (port > 0) 78347dd1d1bSDag-Erling Smørgrav add_one_listen_addr(options, addr, rdomain, port); 78447dd1d1bSDag-Erling Smørgrav else { 78547dd1d1bSDag-Erling Smørgrav for (i = 0; i < options->num_ports; i++) { 78647dd1d1bSDag-Erling Smørgrav add_one_listen_addr(options, addr, rdomain, 78747dd1d1bSDag-Erling Smørgrav options->ports[i]); 78847dd1d1bSDag-Erling Smørgrav } 78947dd1d1bSDag-Erling Smørgrav } 790ca3176e7SBrian Feldman } 791ca3176e7SBrian Feldman 792af12a3e7SDag-Erling Smørgrav static void 79347dd1d1bSDag-Erling Smørgrav add_one_listen_addr(ServerOptions *options, const char *addr, 79447dd1d1bSDag-Erling Smørgrav const char *rdomain, int port) 795ca3176e7SBrian Feldman { 796ca3176e7SBrian Feldman struct addrinfo hints, *ai, *aitop; 797ca3176e7SBrian Feldman char strport[NI_MAXSERV]; 798ca3176e7SBrian Feldman int gaierr; 79947dd1d1bSDag-Erling Smørgrav u_int i; 80047dd1d1bSDag-Erling Smørgrav 80147dd1d1bSDag-Erling Smørgrav /* Find listen_addrs entry for this rdomain */ 80247dd1d1bSDag-Erling Smørgrav for (i = 0; i < options->num_listen_addrs; i++) { 80347dd1d1bSDag-Erling Smørgrav if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL) 80447dd1d1bSDag-Erling Smørgrav break; 80547dd1d1bSDag-Erling Smørgrav if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL) 80647dd1d1bSDag-Erling Smørgrav continue; 80747dd1d1bSDag-Erling Smørgrav if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0) 80847dd1d1bSDag-Erling Smørgrav break; 80947dd1d1bSDag-Erling Smørgrav } 81047dd1d1bSDag-Erling Smørgrav if (i >= options->num_listen_addrs) { 81147dd1d1bSDag-Erling Smørgrav /* No entry for this rdomain; allocate one */ 81247dd1d1bSDag-Erling Smørgrav if (i >= INT_MAX) 81319261079SEd Maste fatal_f("too many listen addresses"); 81447dd1d1bSDag-Erling Smørgrav options->listen_addrs = xrecallocarray(options->listen_addrs, 81547dd1d1bSDag-Erling Smørgrav options->num_listen_addrs, options->num_listen_addrs + 1, 81647dd1d1bSDag-Erling Smørgrav sizeof(*options->listen_addrs)); 81747dd1d1bSDag-Erling Smørgrav i = options->num_listen_addrs++; 81847dd1d1bSDag-Erling Smørgrav if (rdomain != NULL) 81947dd1d1bSDag-Erling Smørgrav options->listen_addrs[i].rdomain = xstrdup(rdomain); 82047dd1d1bSDag-Erling Smørgrav } 82147dd1d1bSDag-Erling Smørgrav /* options->listen_addrs[i] points to the addresses for this rdomain */ 822ca3176e7SBrian Feldman 823511b41d2SMark Murray memset(&hints, 0, sizeof(hints)); 824aa49c926SDag-Erling Smørgrav hints.ai_family = options->address_family; 825511b41d2SMark Murray hints.ai_socktype = SOCK_STREAM; 826511b41d2SMark Murray hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0; 827cce7d346SDag-Erling Smørgrav snprintf(strport, sizeof strport, "%d", port); 828511b41d2SMark Murray if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0) 829ca3176e7SBrian Feldman fatal("bad addr or host: %s (%s)", 830511b41d2SMark Murray addr ? addr : "<NULL>", 831d4af9e69SDag-Erling Smørgrav ssh_gai_strerror(gaierr)); 832511b41d2SMark Murray for (ai = aitop; ai->ai_next; ai = ai->ai_next) 833511b41d2SMark Murray ; 83447dd1d1bSDag-Erling Smørgrav ai->ai_next = options->listen_addrs[i].addrs; 83547dd1d1bSDag-Erling Smørgrav options->listen_addrs[i].addrs = aitop; 83647dd1d1bSDag-Erling Smørgrav } 83747dd1d1bSDag-Erling Smørgrav 83847dd1d1bSDag-Erling Smørgrav /* Returns nonzero if the routing domain name is valid */ 83947dd1d1bSDag-Erling Smørgrav static int 84047dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name) 84147dd1d1bSDag-Erling Smørgrav { 84247dd1d1bSDag-Erling Smørgrav #if defined(HAVE_SYS_VALID_RDOMAIN) 84347dd1d1bSDag-Erling Smørgrav return sys_valid_rdomain(name); 84447dd1d1bSDag-Erling Smørgrav #elif defined(__OpenBSD__) 84547dd1d1bSDag-Erling Smørgrav const char *errstr; 84647dd1d1bSDag-Erling Smørgrav long long num; 84747dd1d1bSDag-Erling Smørgrav struct rt_tableinfo info; 84847dd1d1bSDag-Erling Smørgrav int mib[6]; 84947dd1d1bSDag-Erling Smørgrav size_t miblen = sizeof(mib); 85047dd1d1bSDag-Erling Smørgrav 85147dd1d1bSDag-Erling Smørgrav if (name == NULL) 85247dd1d1bSDag-Erling Smørgrav return 1; 85347dd1d1bSDag-Erling Smørgrav 85447dd1d1bSDag-Erling Smørgrav num = strtonum(name, 0, 255, &errstr); 85547dd1d1bSDag-Erling Smørgrav if (errstr != NULL) 85647dd1d1bSDag-Erling Smørgrav return 0; 85747dd1d1bSDag-Erling Smørgrav 85847dd1d1bSDag-Erling Smørgrav /* Check whether the table actually exists */ 85947dd1d1bSDag-Erling Smørgrav memset(mib, 0, sizeof(mib)); 86047dd1d1bSDag-Erling Smørgrav mib[0] = CTL_NET; 86147dd1d1bSDag-Erling Smørgrav mib[1] = PF_ROUTE; 86247dd1d1bSDag-Erling Smørgrav mib[4] = NET_RT_TABLE; 86347dd1d1bSDag-Erling Smørgrav mib[5] = (int)num; 86447dd1d1bSDag-Erling Smørgrav if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1) 86547dd1d1bSDag-Erling Smørgrav return 0; 86647dd1d1bSDag-Erling Smørgrav 86747dd1d1bSDag-Erling Smørgrav return 1; 86847dd1d1bSDag-Erling Smørgrav #else /* defined(__OpenBSD__) */ 86947dd1d1bSDag-Erling Smørgrav error("Routing domains are not supported on this platform"); 87047dd1d1bSDag-Erling Smørgrav return 0; 87147dd1d1bSDag-Erling Smørgrav #endif 872511b41d2SMark Murray } 873511b41d2SMark Murray 874557f75e5SDag-Erling Smørgrav /* 875557f75e5SDag-Erling Smørgrav * Queue a ListenAddress to be processed once we have all of the Ports 876557f75e5SDag-Erling Smørgrav * and AddressFamily options. 877557f75e5SDag-Erling Smørgrav */ 878557f75e5SDag-Erling Smørgrav static void 87947dd1d1bSDag-Erling Smørgrav queue_listen_addr(ServerOptions *options, const char *addr, 88047dd1d1bSDag-Erling Smørgrav const char *rdomain, int port) 881557f75e5SDag-Erling Smørgrav { 88247dd1d1bSDag-Erling Smørgrav struct queued_listenaddr *qla; 88347dd1d1bSDag-Erling Smørgrav 88447dd1d1bSDag-Erling Smørgrav options->queued_listen_addrs = xrecallocarray( 88547dd1d1bSDag-Erling Smørgrav options->queued_listen_addrs, 88647dd1d1bSDag-Erling Smørgrav options->num_queued_listens, options->num_queued_listens + 1, 88747dd1d1bSDag-Erling Smørgrav sizeof(*options->queued_listen_addrs)); 88847dd1d1bSDag-Erling Smørgrav qla = &options->queued_listen_addrs[options->num_queued_listens++]; 88947dd1d1bSDag-Erling Smørgrav qla->addr = xstrdup(addr); 89047dd1d1bSDag-Erling Smørgrav qla->port = port; 89147dd1d1bSDag-Erling Smørgrav qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain); 892557f75e5SDag-Erling Smørgrav } 893557f75e5SDag-Erling Smørgrav 894557f75e5SDag-Erling Smørgrav /* 895557f75e5SDag-Erling Smørgrav * Process queued (text) ListenAddress entries. 896557f75e5SDag-Erling Smørgrav */ 897557f75e5SDag-Erling Smørgrav static void 898557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(ServerOptions *options) 899557f75e5SDag-Erling Smørgrav { 900557f75e5SDag-Erling Smørgrav u_int i; 90147dd1d1bSDag-Erling Smørgrav struct queued_listenaddr *qla; 902557f75e5SDag-Erling Smørgrav 903557f75e5SDag-Erling Smørgrav if (options->num_ports == 0) 904557f75e5SDag-Erling Smørgrav options->ports[options->num_ports++] = SSH_DEFAULT_PORT; 905557f75e5SDag-Erling Smørgrav if (options->address_family == -1) 906557f75e5SDag-Erling Smørgrav options->address_family = AF_UNSPEC; 907557f75e5SDag-Erling Smørgrav 908557f75e5SDag-Erling Smørgrav for (i = 0; i < options->num_queued_listens; i++) { 90947dd1d1bSDag-Erling Smørgrav qla = &options->queued_listen_addrs[i]; 91047dd1d1bSDag-Erling Smørgrav add_listen_addr(options, qla->addr, qla->rdomain, qla->port); 91147dd1d1bSDag-Erling Smørgrav free(qla->addr); 91247dd1d1bSDag-Erling Smørgrav free(qla->rdomain); 913557f75e5SDag-Erling Smørgrav } 914557f75e5SDag-Erling Smørgrav free(options->queued_listen_addrs); 915557f75e5SDag-Erling Smørgrav options->queued_listen_addrs = NULL; 916557f75e5SDag-Erling Smørgrav options->num_queued_listens = 0; 917557f75e5SDag-Erling Smørgrav } 918557f75e5SDag-Erling Smørgrav 9194f52dfbbSDag-Erling Smørgrav /* 920190cef3dSDag-Erling Smørgrav * Inform channels layer of permitopen options for a single forwarding 921190cef3dSDag-Erling Smørgrav * direction (local/remote). 922190cef3dSDag-Erling Smørgrav */ 923190cef3dSDag-Erling Smørgrav static void 924190cef3dSDag-Erling Smørgrav process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode, 925190cef3dSDag-Erling Smørgrav char **opens, u_int num_opens) 926190cef3dSDag-Erling Smørgrav { 927190cef3dSDag-Erling Smørgrav u_int i; 928190cef3dSDag-Erling Smørgrav int port; 9291323ec57SEd Maste char *host, *arg, *oarg; 930190cef3dSDag-Erling Smørgrav int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE; 931190cef3dSDag-Erling Smørgrav const char *what = lookup_opcode_name(opcode); 932190cef3dSDag-Erling Smørgrav 933190cef3dSDag-Erling Smørgrav channel_clear_permission(ssh, FORWARD_ADM, where); 934190cef3dSDag-Erling Smørgrav if (num_opens == 0) 935190cef3dSDag-Erling Smørgrav return; /* permit any */ 936190cef3dSDag-Erling Smørgrav 937190cef3dSDag-Erling Smørgrav /* handle keywords: "any" / "none" */ 938190cef3dSDag-Erling Smørgrav if (num_opens == 1 && strcmp(opens[0], "any") == 0) 939190cef3dSDag-Erling Smørgrav return; 940190cef3dSDag-Erling Smørgrav if (num_opens == 1 && strcmp(opens[0], "none") == 0) { 941190cef3dSDag-Erling Smørgrav channel_disable_admin(ssh, where); 942190cef3dSDag-Erling Smørgrav return; 943190cef3dSDag-Erling Smørgrav } 944190cef3dSDag-Erling Smørgrav /* Otherwise treat it as a list of permitted host:port */ 945190cef3dSDag-Erling Smørgrav for (i = 0; i < num_opens; i++) { 946190cef3dSDag-Erling Smørgrav oarg = arg = xstrdup(opens[i]); 9471323ec57SEd Maste host = hpdelim(&arg); 9481323ec57SEd Maste if (host == NULL) 94919261079SEd Maste fatal_f("missing host in %s", what); 950190cef3dSDag-Erling Smørgrav host = cleanhostname(host); 951190cef3dSDag-Erling Smørgrav if (arg == NULL || ((port = permitopen_port(arg)) < 0)) 95219261079SEd Maste fatal_f("bad port number in %s", what); 953190cef3dSDag-Erling Smørgrav /* Send it to channels layer */ 954190cef3dSDag-Erling Smørgrav channel_add_permission(ssh, FORWARD_ADM, 955190cef3dSDag-Erling Smørgrav where, host, port); 956190cef3dSDag-Erling Smørgrav free(oarg); 957190cef3dSDag-Erling Smørgrav } 958190cef3dSDag-Erling Smørgrav } 959190cef3dSDag-Erling Smørgrav 960190cef3dSDag-Erling Smørgrav /* 9614f52dfbbSDag-Erling Smørgrav * Inform channels layer of permitopen options from configuration. 9624f52dfbbSDag-Erling Smørgrav */ 9634f52dfbbSDag-Erling Smørgrav void 9644f52dfbbSDag-Erling Smørgrav process_permitopen(struct ssh *ssh, ServerOptions *options) 9654f52dfbbSDag-Erling Smørgrav { 966190cef3dSDag-Erling Smørgrav process_permitopen_list(ssh, sPermitOpen, 967190cef3dSDag-Erling Smørgrav options->permitted_opens, options->num_permitted_opens); 968190cef3dSDag-Erling Smørgrav process_permitopen_list(ssh, sPermitListen, 969190cef3dSDag-Erling Smørgrav options->permitted_listens, 970190cef3dSDag-Erling Smørgrav options->num_permitted_listens); 9714f52dfbbSDag-Erling Smørgrav } 9724f52dfbbSDag-Erling Smørgrav 973f374ba41SEd Maste void 974f374ba41SEd Maste process_channel_timeouts(struct ssh *ssh, ServerOptions *options) 975f374ba41SEd Maste { 976535af610SEd Maste int secs; 977535af610SEd Maste u_int i; 978f374ba41SEd Maste char *type; 979f374ba41SEd Maste 980f374ba41SEd Maste debug3_f("setting %u timeouts", options->num_channel_timeouts); 981f374ba41SEd Maste channel_clear_timeouts(ssh); 982f374ba41SEd Maste for (i = 0; i < options->num_channel_timeouts; i++) { 983069ac184SEd Maste if (parse_pattern_interval(options->channel_timeouts[i], 984f374ba41SEd Maste &type, &secs) != 0) { 985f374ba41SEd Maste fatal_f("internal error: bad timeout %s", 986f374ba41SEd Maste options->channel_timeouts[i]); 987f374ba41SEd Maste } 988f374ba41SEd Maste channel_add_timeout(ssh, type, secs); 989f374ba41SEd Maste free(type); 990f374ba41SEd Maste } 991f374ba41SEd Maste } 992f374ba41SEd Maste 993462c32cbSDag-Erling Smørgrav struct connection_info * 99419261079SEd Maste get_connection_info(struct ssh *ssh, int populate, int use_dns) 995462c32cbSDag-Erling Smørgrav { 996462c32cbSDag-Erling Smørgrav static struct connection_info ci; 997462c32cbSDag-Erling Smørgrav 99819261079SEd Maste if (ssh == NULL || !populate) 999462c32cbSDag-Erling Smørgrav return &ci; 1000076ad2f8SDag-Erling Smørgrav ci.host = auth_get_canonical_hostname(ssh, use_dns); 1001076ad2f8SDag-Erling Smørgrav ci.address = ssh_remote_ipaddr(ssh); 1002076ad2f8SDag-Erling Smørgrav ci.laddress = ssh_local_ipaddr(ssh); 1003076ad2f8SDag-Erling Smørgrav ci.lport = ssh_local_port(ssh); 100447dd1d1bSDag-Erling Smørgrav ci.rdomain = ssh_packet_rdomain_in(ssh); 1005462c32cbSDag-Erling Smørgrav return &ci; 1006462c32cbSDag-Erling Smørgrav } 1007462c32cbSDag-Erling Smørgrav 1008333ee039SDag-Erling Smørgrav /* 1009333ee039SDag-Erling Smørgrav * The strategy for the Match blocks is that the config file is parsed twice. 1010333ee039SDag-Erling Smørgrav * 1011333ee039SDag-Erling Smørgrav * The first time is at startup. activep is initialized to 1 and the 1012333ee039SDag-Erling Smørgrav * directives in the global context are processed and acted on. Hitting a 1013333ee039SDag-Erling Smørgrav * Match directive unsets activep and the directives inside the block are 1014333ee039SDag-Erling Smørgrav * checked for syntax only. 1015333ee039SDag-Erling Smørgrav * 1016333ee039SDag-Erling Smørgrav * The second time is after a connection has been established but before 1017333ee039SDag-Erling Smørgrav * authentication. activep is initialized to 2 and global config directives 1018333ee039SDag-Erling Smørgrav * are ignored since they have already been processed. If the criteria in a 1019333ee039SDag-Erling Smørgrav * Match block is met, activep is set and the subsequent directives 1020333ee039SDag-Erling Smørgrav * processed and actioned until EOF or another Match block unsets it. Any 1021333ee039SDag-Erling Smørgrav * options set are copied into the main server config. 1022333ee039SDag-Erling Smørgrav * 1023333ee039SDag-Erling Smørgrav * Potential additions/improvements: 1024ca86bcf2SDag-Erling Smørgrav * - Add Match support for pre-kex directives, eg. Ciphers. 1025333ee039SDag-Erling Smørgrav * 1026333ee039SDag-Erling Smørgrav * - Add a Tag directive (idea from David Leonard) ala pf, eg: 1027333ee039SDag-Erling Smørgrav * Match Address 192.168.0.* 1028333ee039SDag-Erling Smørgrav * Tag trusted 1029333ee039SDag-Erling Smørgrav * Match Group wheel 1030333ee039SDag-Erling Smørgrav * Tag trusted 1031333ee039SDag-Erling Smørgrav * Match Tag trusted 1032333ee039SDag-Erling Smørgrav * AllowTcpForwarding yes 1033333ee039SDag-Erling Smørgrav * GatewayPorts clientspecified 1034333ee039SDag-Erling Smørgrav * [...] 1035333ee039SDag-Erling Smørgrav * 1036333ee039SDag-Erling Smørgrav * - Add a PermittedChannelRequests directive 1037333ee039SDag-Erling Smørgrav * Match Group shell 1038333ee039SDag-Erling Smørgrav * PermittedChannelRequests session,forwarded-tcpip 1039333ee039SDag-Erling Smørgrav */ 1040333ee039SDag-Erling Smørgrav 1041333ee039SDag-Erling Smørgrav static int 1042333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user) 1043333ee039SDag-Erling Smørgrav { 1044333ee039SDag-Erling Smørgrav int result = 0; 1045333ee039SDag-Erling Smørgrav struct passwd *pw; 1046333ee039SDag-Erling Smørgrav 1047333ee039SDag-Erling Smørgrav if (user == NULL) 1048333ee039SDag-Erling Smørgrav goto out; 1049333ee039SDag-Erling Smørgrav 1050333ee039SDag-Erling Smørgrav if ((pw = getpwnam(user)) == NULL) { 1051333ee039SDag-Erling Smørgrav debug("Can't match group at line %d because user %.100s does " 1052333ee039SDag-Erling Smørgrav "not exist", line, user); 1053333ee039SDag-Erling Smørgrav } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) { 1054333ee039SDag-Erling Smørgrav debug("Can't Match group because user %.100s not in any group " 1055333ee039SDag-Erling Smørgrav "at line %d", user, line); 1056d4af9e69SDag-Erling Smørgrav } else if (ga_match_pattern_list(grps) != 1) { 1057d4af9e69SDag-Erling Smørgrav debug("user %.100s does not match group list %.100s at line %d", 1058d4af9e69SDag-Erling Smørgrav user, grps, line); 1059333ee039SDag-Erling Smørgrav } else { 1060d4af9e69SDag-Erling Smørgrav debug("user %.100s matched group list %.100s at line %d", user, 1061d4af9e69SDag-Erling Smørgrav grps, line); 1062333ee039SDag-Erling Smørgrav result = 1; 1063333ee039SDag-Erling Smørgrav } 1064333ee039SDag-Erling Smørgrav out: 1065333ee039SDag-Erling Smørgrav ga_free(); 1066333ee039SDag-Erling Smørgrav return result; 1067333ee039SDag-Erling Smørgrav } 1068333ee039SDag-Erling Smørgrav 106947dd1d1bSDag-Erling Smørgrav static void 107047dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib) 107147dd1d1bSDag-Erling Smørgrav { 107247dd1d1bSDag-Erling Smørgrav fatal("'Match %s' in configuration but '%s' not in connection " 107347dd1d1bSDag-Erling Smørgrav "test specification.", criteria, attrib); 107447dd1d1bSDag-Erling Smørgrav } 107547dd1d1bSDag-Erling Smørgrav 1076462c32cbSDag-Erling Smørgrav /* 10776888a9beSDag-Erling Smørgrav * All of the attributes on a single Match line are ANDed together, so we need 1078f7167e0eSDag-Erling Smørgrav * to check every attribute and set the result to zero if any attribute does 10796888a9beSDag-Erling Smørgrav * not match. 1080462c32cbSDag-Erling Smørgrav */ 1081333ee039SDag-Erling Smørgrav static int 1082462c32cbSDag-Erling Smørgrav match_cfg_line(char **condition, int line, struct connection_info *ci) 1083333ee039SDag-Erling Smørgrav { 1084f7167e0eSDag-Erling Smørgrav int result = 1, attributes = 0, port; 1085333ee039SDag-Erling Smørgrav char *arg, *attrib, *cp = *condition; 1086333ee039SDag-Erling Smørgrav 1087462c32cbSDag-Erling Smørgrav if (ci == NULL) 1088333ee039SDag-Erling Smørgrav debug3("checking syntax for 'Match %s'", cp); 1089333ee039SDag-Erling Smørgrav else 1090462c32cbSDag-Erling Smørgrav debug3("checking match for '%s' user %s host %s addr %s " 1091462c32cbSDag-Erling Smørgrav "laddr %s lport %d", cp, ci->user ? ci->user : "(null)", 1092462c32cbSDag-Erling Smørgrav ci->host ? ci->host : "(null)", 1093462c32cbSDag-Erling Smørgrav ci->address ? ci->address : "(null)", 1094462c32cbSDag-Erling Smørgrav ci->laddress ? ci->laddress : "(null)", ci->lport); 1095333ee039SDag-Erling Smørgrav 1096333ee039SDag-Erling Smørgrav while ((attrib = strdelim(&cp)) && *attrib != '\0') { 109719261079SEd Maste /* Terminate on comment */ 109819261079SEd Maste if (*attrib == '#') { 109919261079SEd Maste cp = NULL; /* mark all arguments consumed */ 110019261079SEd Maste break; 110119261079SEd Maste } 110219261079SEd Maste arg = NULL; 1103f7167e0eSDag-Erling Smørgrav attributes++; 110419261079SEd Maste /* Criterion "all" has no argument and must appear alone */ 1105f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "all") == 0) { 110619261079SEd Maste if (attributes > 1 || ((arg = strdelim(&cp)) != NULL && 110719261079SEd Maste *arg != '\0' && *arg != '#')) { 1108f7167e0eSDag-Erling Smørgrav error("'all' cannot be combined with other " 1109f7167e0eSDag-Erling Smørgrav "Match attributes"); 1110f7167e0eSDag-Erling Smørgrav return -1; 1111f7167e0eSDag-Erling Smørgrav } 111219261079SEd Maste if (arg != NULL && *arg == '#') 111319261079SEd Maste cp = NULL; /* mark all arguments consumed */ 1114f7167e0eSDag-Erling Smørgrav *condition = cp; 1115f7167e0eSDag-Erling Smørgrav return 1; 1116f7167e0eSDag-Erling Smørgrav } 111719261079SEd Maste /* All other criteria require an argument */ 111819261079SEd Maste if ((arg = strdelim(&cp)) == NULL || 111919261079SEd Maste *arg == '\0' || *arg == '#') { 1120333ee039SDag-Erling Smørgrav error("Missing Match criteria for %s", attrib); 1121333ee039SDag-Erling Smørgrav return -1; 1122333ee039SDag-Erling Smørgrav } 1123333ee039SDag-Erling Smørgrav if (strcasecmp(attrib, "user") == 0) { 112419261079SEd Maste if (ci == NULL || (ci->test && ci->user == NULL)) { 1125333ee039SDag-Erling Smørgrav result = 0; 1126333ee039SDag-Erling Smørgrav continue; 1127333ee039SDag-Erling Smørgrav } 112847dd1d1bSDag-Erling Smørgrav if (ci->user == NULL) 112947dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("User", "user"); 113019261079SEd Maste if (match_usergroup_pattern_list(ci->user, arg) != 1) 1131333ee039SDag-Erling Smørgrav result = 0; 1132333ee039SDag-Erling Smørgrav else 1133333ee039SDag-Erling Smørgrav debug("user %.100s matched 'User %.100s' at " 1134462c32cbSDag-Erling Smørgrav "line %d", ci->user, arg, line); 1135333ee039SDag-Erling Smørgrav } else if (strcasecmp(attrib, "group") == 0) { 113619261079SEd Maste if (ci == NULL || (ci->test && ci->user == NULL)) { 1137462c32cbSDag-Erling Smørgrav result = 0; 1138462c32cbSDag-Erling Smørgrav continue; 1139462c32cbSDag-Erling Smørgrav } 114047dd1d1bSDag-Erling Smørgrav if (ci->user == NULL) 114147dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("Group", "user"); 1142462c32cbSDag-Erling Smørgrav switch (match_cfg_line_group(arg, line, ci->user)) { 1143333ee039SDag-Erling Smørgrav case -1: 1144333ee039SDag-Erling Smørgrav return -1; 1145333ee039SDag-Erling Smørgrav case 0: 1146333ee039SDag-Erling Smørgrav result = 0; 1147333ee039SDag-Erling Smørgrav } 1148333ee039SDag-Erling Smørgrav } else if (strcasecmp(attrib, "host") == 0) { 114919261079SEd Maste if (ci == NULL || (ci->test && ci->host == NULL)) { 1150333ee039SDag-Erling Smørgrav result = 0; 1151333ee039SDag-Erling Smørgrav continue; 1152333ee039SDag-Erling Smørgrav } 115347dd1d1bSDag-Erling Smørgrav if (ci->host == NULL) 115447dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("Host", "host"); 1155557f75e5SDag-Erling Smørgrav if (match_hostname(ci->host, arg) != 1) 1156333ee039SDag-Erling Smørgrav result = 0; 1157333ee039SDag-Erling Smørgrav else 1158333ee039SDag-Erling Smørgrav debug("connection from %.100s matched 'Host " 1159462c32cbSDag-Erling Smørgrav "%.100s' at line %d", ci->host, arg, line); 1160333ee039SDag-Erling Smørgrav } else if (strcasecmp(attrib, "address") == 0) { 116119261079SEd Maste if (ci == NULL || (ci->test && ci->address == NULL)) { 116219261079SEd Maste if (addr_match_list(NULL, arg) != 0) 116319261079SEd Maste fatal("Invalid Match address argument " 116419261079SEd Maste "'%s' at line %d", arg, line); 1165462c32cbSDag-Erling Smørgrav result = 0; 1166462c32cbSDag-Erling Smørgrav continue; 1167462c32cbSDag-Erling Smørgrav } 116847dd1d1bSDag-Erling Smørgrav if (ci->address == NULL) 116947dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("Address", "addr"); 1170462c32cbSDag-Erling Smørgrav switch (addr_match_list(ci->address, arg)) { 1171d4af9e69SDag-Erling Smørgrav case 1: 1172333ee039SDag-Erling Smørgrav debug("connection from %.100s matched 'Address " 1173462c32cbSDag-Erling Smørgrav "%.100s' at line %d", ci->address, arg, line); 1174d4af9e69SDag-Erling Smørgrav break; 1175d4af9e69SDag-Erling Smørgrav case 0: 1176d4af9e69SDag-Erling Smørgrav case -1: 1177d4af9e69SDag-Erling Smørgrav result = 0; 1178d4af9e69SDag-Erling Smørgrav break; 1179d4af9e69SDag-Erling Smørgrav case -2: 1180d4af9e69SDag-Erling Smørgrav return -1; 1181d4af9e69SDag-Erling Smørgrav } 1182462c32cbSDag-Erling Smørgrav } else if (strcasecmp(attrib, "localaddress") == 0){ 118319261079SEd Maste if (ci == NULL || (ci->test && ci->laddress == NULL)) { 118419261079SEd Maste if (addr_match_list(NULL, arg) != 0) 118519261079SEd Maste fatal("Invalid Match localaddress " 118619261079SEd Maste "argument '%s' at line %d", arg, 118719261079SEd Maste line); 1188462c32cbSDag-Erling Smørgrav result = 0; 1189462c32cbSDag-Erling Smørgrav continue; 1190462c32cbSDag-Erling Smørgrav } 119147dd1d1bSDag-Erling Smørgrav if (ci->laddress == NULL) 119247dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("LocalAddress", 119347dd1d1bSDag-Erling Smørgrav "laddr"); 1194462c32cbSDag-Erling Smørgrav switch (addr_match_list(ci->laddress, arg)) { 1195462c32cbSDag-Erling Smørgrav case 1: 1196462c32cbSDag-Erling Smørgrav debug("connection from %.100s matched " 1197462c32cbSDag-Erling Smørgrav "'LocalAddress %.100s' at line %d", 1198462c32cbSDag-Erling Smørgrav ci->laddress, arg, line); 1199462c32cbSDag-Erling Smørgrav break; 1200462c32cbSDag-Erling Smørgrav case 0: 1201462c32cbSDag-Erling Smørgrav case -1: 1202462c32cbSDag-Erling Smørgrav result = 0; 1203462c32cbSDag-Erling Smørgrav break; 1204462c32cbSDag-Erling Smørgrav case -2: 1205462c32cbSDag-Erling Smørgrav return -1; 1206462c32cbSDag-Erling Smørgrav } 1207462c32cbSDag-Erling Smørgrav } else if (strcasecmp(attrib, "localport") == 0) { 1208462c32cbSDag-Erling Smørgrav if ((port = a2port(arg)) == -1) { 1209462c32cbSDag-Erling Smørgrav error("Invalid LocalPort '%s' on Match line", 1210462c32cbSDag-Erling Smørgrav arg); 1211462c32cbSDag-Erling Smørgrav return -1; 1212462c32cbSDag-Erling Smørgrav } 121319261079SEd Maste if (ci == NULL || (ci->test && ci->lport == -1)) { 1214462c32cbSDag-Erling Smørgrav result = 0; 1215462c32cbSDag-Erling Smørgrav continue; 1216462c32cbSDag-Erling Smørgrav } 121747dd1d1bSDag-Erling Smørgrav if (ci->lport == 0) 121847dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("LocalPort", "lport"); 1219462c32cbSDag-Erling Smørgrav /* TODO support port lists */ 1220462c32cbSDag-Erling Smørgrav if (port == ci->lport) 1221462c32cbSDag-Erling Smørgrav debug("connection from %.100s matched " 1222462c32cbSDag-Erling Smørgrav "'LocalPort %d' at line %d", 1223462c32cbSDag-Erling Smørgrav ci->laddress, port, line); 1224462c32cbSDag-Erling Smørgrav else 1225462c32cbSDag-Erling Smørgrav result = 0; 122647dd1d1bSDag-Erling Smørgrav } else if (strcasecmp(attrib, "rdomain") == 0) { 122719261079SEd Maste if (ci == NULL || (ci->test && ci->rdomain == NULL)) { 122847dd1d1bSDag-Erling Smørgrav result = 0; 122947dd1d1bSDag-Erling Smørgrav continue; 123047dd1d1bSDag-Erling Smørgrav } 123119261079SEd Maste if (ci->rdomain == NULL) 123219261079SEd Maste match_test_missing_fatal("RDomain", "rdomain"); 123347dd1d1bSDag-Erling Smørgrav if (match_pattern_list(ci->rdomain, arg, 0) != 1) 123447dd1d1bSDag-Erling Smørgrav result = 0; 123547dd1d1bSDag-Erling Smørgrav else 123647dd1d1bSDag-Erling Smørgrav debug("user %.100s matched 'RDomain %.100s' at " 123747dd1d1bSDag-Erling Smørgrav "line %d", ci->rdomain, arg, line); 1238333ee039SDag-Erling Smørgrav } else { 1239333ee039SDag-Erling Smørgrav error("Unsupported Match attribute %s", attrib); 1240333ee039SDag-Erling Smørgrav return -1; 1241333ee039SDag-Erling Smørgrav } 1242333ee039SDag-Erling Smørgrav } 1243f7167e0eSDag-Erling Smørgrav if (attributes == 0) { 1244f7167e0eSDag-Erling Smørgrav error("One or more attributes required for Match"); 1245f7167e0eSDag-Erling Smørgrav return -1; 1246f7167e0eSDag-Erling Smørgrav } 1247462c32cbSDag-Erling Smørgrav if (ci != NULL) 1248333ee039SDag-Erling Smørgrav debug3("match %sfound", result ? "" : "not "); 1249333ee039SDag-Erling Smørgrav *condition = cp; 1250333ee039SDag-Erling Smørgrav return result; 1251333ee039SDag-Erling Smørgrav } 1252333ee039SDag-Erling Smørgrav 1253333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n" 1254333ee039SDag-Erling Smørgrav 1255e146993eSDag-Erling Smørgrav /* Multistate option parsing */ 1256e146993eSDag-Erling Smørgrav struct multistate { 1257e146993eSDag-Erling Smørgrav char *key; 1258e146993eSDag-Erling Smørgrav int value; 1259e146993eSDag-Erling Smørgrav }; 126047dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = { 126147dd1d1bSDag-Erling Smørgrav { "yes", 1 }, 126247dd1d1bSDag-Erling Smørgrav { "no", 0 }, 126347dd1d1bSDag-Erling Smørgrav { NULL, -1 } 126447dd1d1bSDag-Erling Smørgrav }; 126519261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = { 126619261079SEd Maste { "yes", IGNORE_RHOSTS_YES }, 126719261079SEd Maste { "no", IGNORE_RHOSTS_NO }, 126819261079SEd Maste { "shosts-only", IGNORE_RHOSTS_SHOSTS }, 126919261079SEd Maste { NULL, -1 } 127019261079SEd Maste }; 1271e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = { 1272e146993eSDag-Erling Smørgrav { "inet", AF_INET }, 1273e146993eSDag-Erling Smørgrav { "inet6", AF_INET6 }, 1274e146993eSDag-Erling Smørgrav { "any", AF_UNSPEC }, 1275e146993eSDag-Erling Smørgrav { NULL, -1 } 1276e146993eSDag-Erling Smørgrav }; 1277e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = { 1278e146993eSDag-Erling Smørgrav { "without-password", PERMIT_NO_PASSWD }, 1279eccfee6eSDag-Erling Smørgrav { "prohibit-password", PERMIT_NO_PASSWD }, 1280e146993eSDag-Erling Smørgrav { "forced-commands-only", PERMIT_FORCED_ONLY }, 1281e146993eSDag-Erling Smørgrav { "yes", PERMIT_YES }, 1282e146993eSDag-Erling Smørgrav { "no", PERMIT_NO }, 1283e146993eSDag-Erling Smørgrav { NULL, -1 } 1284e146993eSDag-Erling Smørgrav }; 1285e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = { 128619261079SEd Maste #ifdef WITH_ZLIB 1287ca86bcf2SDag-Erling Smørgrav { "yes", COMP_DELAYED }, 1288e146993eSDag-Erling Smørgrav { "delayed", COMP_DELAYED }, 128919261079SEd Maste #endif 1290e146993eSDag-Erling Smørgrav { "no", COMP_NONE }, 1291e146993eSDag-Erling Smørgrav { NULL, -1 } 1292e146993eSDag-Erling Smørgrav }; 1293e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = { 1294e146993eSDag-Erling Smørgrav { "clientspecified", 2 }, 1295e146993eSDag-Erling Smørgrav { "yes", 1 }, 1296e146993eSDag-Erling Smørgrav { "no", 0 }, 1297e146993eSDag-Erling Smørgrav { NULL, -1 } 1298e146993eSDag-Erling Smørgrav }; 12996888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = { 13006888a9beSDag-Erling Smørgrav { "yes", FORWARD_ALLOW }, 13016888a9beSDag-Erling Smørgrav { "all", FORWARD_ALLOW }, 13026888a9beSDag-Erling Smørgrav { "no", FORWARD_DENY }, 13036888a9beSDag-Erling Smørgrav { "remote", FORWARD_REMOTE }, 13046888a9beSDag-Erling Smørgrav { "local", FORWARD_LOCAL }, 13056888a9beSDag-Erling Smørgrav { NULL, -1 } 13066888a9beSDag-Erling Smørgrav }; 1307e146993eSDag-Erling Smørgrav 130819261079SEd Maste static int 130919261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line, 1310462c32cbSDag-Erling Smørgrav const char *filename, int linenum, int *activep, 131119261079SEd Maste struct connection_info *connectinfo, int *inc_flags, int depth, 131219261079SEd Maste struct include_list *includes) 1313511b41d2SMark Murray { 13141323ec57SEd Maste char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword; 1315*a91a2465SEd Maste int cmdline = 0, *intptr, value, value2, n, port, oactive, r; 1316*a91a2465SEd Maste int ca_only = 0, found = 0; 1317d4af9e69SDag-Erling Smørgrav SyslogFacility *log_facility_ptr; 1318d4af9e69SDag-Erling Smørgrav LogLevel *log_level_ptr; 1319511b41d2SMark Murray ServerOpCodes opcode; 1320*a91a2465SEd Maste u_int i, *uintptr, flags = 0; 1321333ee039SDag-Erling Smørgrav size_t len; 1322e4a9863fSDag-Erling Smørgrav long long val64; 1323e146993eSDag-Erling Smørgrav const struct multistate *multistate_ptr; 132447dd1d1bSDag-Erling Smørgrav const char *errstr; 132519261079SEd Maste struct include_item *item; 132619261079SEd Maste glob_t gbuf; 132719261079SEd Maste char **oav = NULL, **av; 132819261079SEd Maste int oac = 0, ac; 132919261079SEd Maste int ret = -1; 1330*a91a2465SEd Maste char **strs = NULL; /* string array arguments; freed implicitly */ 1331*a91a2465SEd Maste u_int nstrs = 0; 1332511b41d2SMark Murray 1333d93a896eSDag-Erling Smørgrav /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ 1334d93a896eSDag-Erling Smørgrav if ((len = strlen(line)) == 0) 1335d93a896eSDag-Erling Smørgrav return 0; 1336d93a896eSDag-Erling Smørgrav for (len--; len > 0; len--) { 1337d93a896eSDag-Erling Smørgrav if (strchr(WHITESPACE "\f", line[len]) == NULL) 1338d93a896eSDag-Erling Smørgrav break; 1339d93a896eSDag-Erling Smørgrav line[len] = '\0'; 1340d93a896eSDag-Erling Smørgrav } 1341d93a896eSDag-Erling Smørgrav 134219261079SEd Maste str = line; 134319261079SEd Maste if ((keyword = strdelim(&str)) == NULL) 1344333ee039SDag-Erling Smørgrav return 0; 1345c2d3a559SKris Kennaway /* Ignore leading whitespace */ 134619261079SEd Maste if (*keyword == '\0') 134719261079SEd Maste keyword = strdelim(&str); 134819261079SEd Maste if (!keyword || !*keyword || *keyword == '#') 1349af12a3e7SDag-Erling Smørgrav return 0; 135019261079SEd Maste if (str == NULL || *str == '\0') { 135119261079SEd Maste error("%s line %d: no argument after keyword \"%s\"", 135219261079SEd Maste filename, linenum, keyword); 135319261079SEd Maste return -1; 135419261079SEd Maste } 1355ca3176e7SBrian Feldman intptr = NULL; 1356ca3176e7SBrian Feldman charptr = NULL; 135719261079SEd Maste opcode = parse_token(keyword, filename, linenum, &flags); 135819261079SEd Maste 135919261079SEd Maste if (argv_split(str, &oac, &oav, 1) != 0) { 136019261079SEd Maste error("%s line %d: invalid quotes", filename, linenum); 136119261079SEd Maste return -1; 136219261079SEd Maste } 136319261079SEd Maste ac = oac; 136419261079SEd Maste av = oav; 1365333ee039SDag-Erling Smørgrav 1366333ee039SDag-Erling Smørgrav if (activep == NULL) { /* We are processing a command line directive */ 1367333ee039SDag-Erling Smørgrav cmdline = 1; 1368333ee039SDag-Erling Smørgrav activep = &cmdline; 1369333ee039SDag-Erling Smørgrav } 137019261079SEd Maste if (*activep && opcode != sMatch && opcode != sInclude) 137119261079SEd Maste debug3("%s:%d setting %s %s", filename, linenum, keyword, str); 1372333ee039SDag-Erling Smørgrav if (*activep == 0 && !(flags & SSHCFG_MATCH)) { 1373462c32cbSDag-Erling Smørgrav if (connectinfo == NULL) { 1374333ee039SDag-Erling Smørgrav fatal("%s line %d: Directive '%s' is not allowed " 137519261079SEd Maste "within a Match block", filename, linenum, keyword); 1376333ee039SDag-Erling Smørgrav } else { /* this is a directive we have already processed */ 137719261079SEd Maste ret = 0; 137819261079SEd Maste goto out; 1379333ee039SDag-Erling Smørgrav } 1380333ee039SDag-Erling Smørgrav } 1381333ee039SDag-Erling Smørgrav 1382511b41d2SMark Murray switch (opcode) { 1383989dd127SDag-Erling Smørgrav /* Portable-specific options */ 1384cf2b5f3bSDag-Erling Smørgrav case sUsePAM: 1385cf2b5f3bSDag-Erling Smørgrav intptr = &options->use_pam; 1386989dd127SDag-Erling Smørgrav goto parse_flag; 1387989dd127SDag-Erling Smørgrav 1388989dd127SDag-Erling Smørgrav /* Standard Options */ 1389511b41d2SMark Murray case sBadOption: 139019261079SEd Maste goto out; 1391511b41d2SMark Murray case sPort: 1392511b41d2SMark Murray /* ignore ports from configfile if cmdline specifies ports */ 139319261079SEd Maste if (options->ports_from_cmdline) { 139419261079SEd Maste argv_consume(&ac); 139519261079SEd Maste break; 139619261079SEd Maste } 1397511b41d2SMark Murray if (options->num_ports >= MAX_PORTS) 1398ca3176e7SBrian Feldman fatal("%s line %d: too many ports.", 1399511b41d2SMark Murray filename, linenum); 140019261079SEd Maste arg = argv_next(&ac, &av); 1401c2d3a559SKris Kennaway if (!arg || *arg == '\0') 1402ca3176e7SBrian Feldman fatal("%s line %d: missing port number.", 1403511b41d2SMark Murray filename, linenum); 1404ca3176e7SBrian Feldman options->ports[options->num_ports++] = a2port(arg); 1405cce7d346SDag-Erling Smørgrav if (options->ports[options->num_ports-1] <= 0) 1406ca3176e7SBrian Feldman fatal("%s line %d: Badly formatted port number.", 1407ca3176e7SBrian Feldman filename, linenum); 1408511b41d2SMark Murray break; 1409511b41d2SMark Murray 1410511b41d2SMark Murray case sLoginGraceTime: 1411511b41d2SMark Murray intptr = &options->login_grace_time; 1412af12a3e7SDag-Erling Smørgrav parse_time: 141319261079SEd Maste arg = argv_next(&ac, &av); 1414af12a3e7SDag-Erling Smørgrav if (!arg || *arg == '\0') 1415af12a3e7SDag-Erling Smørgrav fatal("%s line %d: missing time value.", 1416af12a3e7SDag-Erling Smørgrav filename, linenum); 1417af12a3e7SDag-Erling Smørgrav if ((value = convtime(arg)) == -1) 1418af12a3e7SDag-Erling Smørgrav fatal("%s line %d: invalid time value.", 1419af12a3e7SDag-Erling Smørgrav filename, linenum); 1420557f75e5SDag-Erling Smørgrav if (*activep && *intptr == -1) 1421af12a3e7SDag-Erling Smørgrav *intptr = value; 1422af12a3e7SDag-Erling Smørgrav break; 1423511b41d2SMark Murray 1424511b41d2SMark Murray case sListenAddress: 142519261079SEd Maste arg = argv_next(&ac, &av); 1426aa49c926SDag-Erling Smørgrav if (arg == NULL || *arg == '\0') 1427aa49c926SDag-Erling Smørgrav fatal("%s line %d: missing address", 1428511b41d2SMark Murray filename, linenum); 1429d4ecd108SDag-Erling Smørgrav /* check for bare IPv6 address: no "[]" and 2 or more ":" */ 1430d4ecd108SDag-Erling Smørgrav if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL 1431d4ecd108SDag-Erling Smørgrav && strchr(p+1, ':') != NULL) { 143247dd1d1bSDag-Erling Smørgrav port = 0; 143347dd1d1bSDag-Erling Smørgrav p = arg; 143447dd1d1bSDag-Erling Smørgrav } else { 143519261079SEd Maste arg2 = NULL; 14361323ec57SEd Maste p = hpdelim(&arg); 14371323ec57SEd Maste if (p == NULL) 1438aa49c926SDag-Erling Smørgrav fatal("%s line %d: bad address:port usage", 1439ca3176e7SBrian Feldman filename, linenum); 1440aa49c926SDag-Erling Smørgrav p = cleanhostname(p); 1441aa49c926SDag-Erling Smørgrav if (arg == NULL) 1442aa49c926SDag-Erling Smørgrav port = 0; 1443cce7d346SDag-Erling Smørgrav else if ((port = a2port(arg)) <= 0) 144447dd1d1bSDag-Erling Smørgrav fatal("%s line %d: bad port number", 144547dd1d1bSDag-Erling Smørgrav filename, linenum); 144647dd1d1bSDag-Erling Smørgrav } 144747dd1d1bSDag-Erling Smørgrav /* Optional routing table */ 144847dd1d1bSDag-Erling Smørgrav arg2 = NULL; 144919261079SEd Maste if ((arg = argv_next(&ac, &av)) != NULL) { 145047dd1d1bSDag-Erling Smørgrav if (strcmp(arg, "rdomain") != 0 || 145119261079SEd Maste (arg2 = argv_next(&ac, &av)) == NULL) 145247dd1d1bSDag-Erling Smørgrav fatal("%s line %d: bad ListenAddress syntax", 145347dd1d1bSDag-Erling Smørgrav filename, linenum); 145447dd1d1bSDag-Erling Smørgrav if (!valid_rdomain(arg2)) 145547dd1d1bSDag-Erling Smørgrav fatal("%s line %d: bad routing domain", 145647dd1d1bSDag-Erling Smørgrav filename, linenum); 145747dd1d1bSDag-Erling Smørgrav } 145847dd1d1bSDag-Erling Smørgrav queue_listen_addr(options, p, arg2, port); 1459aa49c926SDag-Erling Smørgrav 1460aa49c926SDag-Erling Smørgrav break; 1461aa49c926SDag-Erling Smørgrav 1462aa49c926SDag-Erling Smørgrav case sAddressFamily: 1463e146993eSDag-Erling Smørgrav intptr = &options->address_family; 1464e146993eSDag-Erling Smørgrav multistate_ptr = multistate_addressfamily; 1465e146993eSDag-Erling Smørgrav parse_multistate: 146619261079SEd Maste arg = argv_next(&ac, &av); 1467d4ecd108SDag-Erling Smørgrav if (!arg || *arg == '\0') 1468e146993eSDag-Erling Smørgrav fatal("%s line %d: missing argument.", 1469d4ecd108SDag-Erling Smørgrav filename, linenum); 1470e146993eSDag-Erling Smørgrav value = -1; 1471e146993eSDag-Erling Smørgrav for (i = 0; multistate_ptr[i].key != NULL; i++) { 1472e146993eSDag-Erling Smørgrav if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 1473e146993eSDag-Erling Smørgrav value = multistate_ptr[i].value; 1474e146993eSDag-Erling Smørgrav break; 1475e146993eSDag-Erling Smørgrav } 1476e146993eSDag-Erling Smørgrav } 1477e146993eSDag-Erling Smørgrav if (value == -1) 1478e146993eSDag-Erling Smørgrav fatal("%s line %d: unsupported option \"%s\".", 1479aa49c926SDag-Erling Smørgrav filename, linenum, arg); 1480e146993eSDag-Erling Smørgrav if (*activep && *intptr == -1) 1481aa49c926SDag-Erling Smørgrav *intptr = value; 1482511b41d2SMark Murray break; 1483511b41d2SMark Murray 1484511b41d2SMark Murray case sHostKeyFile: 148519261079SEd Maste arg = argv_next(&ac, &av); 1486ca3176e7SBrian Feldman if (!arg || *arg == '\0') 1487ca3176e7SBrian Feldman fatal("%s line %d: missing file name.", 1488e8aafc91SKris Kennaway filename, linenum); 148919261079SEd Maste if (*activep) { 149019261079SEd Maste servconf_add_hostkey(filename, linenum, 149119261079SEd Maste options, arg, 1); 149219261079SEd Maste } 1493e8aafc91SKris Kennaway break; 1494e8aafc91SKris Kennaway 1495e4a9863fSDag-Erling Smørgrav case sHostKeyAgent: 1496e4a9863fSDag-Erling Smørgrav charptr = &options->host_key_agent; 149719261079SEd Maste arg = argv_next(&ac, &av); 1498e4a9863fSDag-Erling Smørgrav if (!arg || *arg == '\0') 1499e4a9863fSDag-Erling Smørgrav fatal("%s line %d: missing socket name.", 1500e4a9863fSDag-Erling Smørgrav filename, linenum); 1501e4a9863fSDag-Erling Smørgrav if (*activep && *charptr == NULL) 1502e4a9863fSDag-Erling Smørgrav *charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ? 1503e4a9863fSDag-Erling Smørgrav xstrdup(arg) : derelativise_path(arg); 1504e4a9863fSDag-Erling Smørgrav break; 1505e4a9863fSDag-Erling Smørgrav 1506b15c8340SDag-Erling Smørgrav case sHostCertificate: 150719261079SEd Maste arg = argv_next(&ac, &av); 150847dd1d1bSDag-Erling Smørgrav if (!arg || *arg == '\0') 150947dd1d1bSDag-Erling Smørgrav fatal("%s line %d: missing file name.", 151047dd1d1bSDag-Erling Smørgrav filename, linenum); 151147dd1d1bSDag-Erling Smørgrav if (*activep) 151247dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(filename, linenum, options, arg); 151347dd1d1bSDag-Erling Smørgrav break; 1514b15c8340SDag-Erling Smørgrav 1515e8aafc91SKris Kennaway case sPidFile: 1516e8aafc91SKris Kennaway charptr = &options->pid_file; 151747dd1d1bSDag-Erling Smørgrav parse_filename: 151819261079SEd Maste arg = argv_next(&ac, &av); 151947dd1d1bSDag-Erling Smørgrav if (!arg || *arg == '\0') 152047dd1d1bSDag-Erling Smørgrav fatal("%s line %d: missing file name.", 152147dd1d1bSDag-Erling Smørgrav filename, linenum); 152247dd1d1bSDag-Erling Smørgrav if (*activep && *charptr == NULL) { 152347dd1d1bSDag-Erling Smørgrav *charptr = derelativise_path(arg); 152447dd1d1bSDag-Erling Smørgrav /* increase optional counter */ 152547dd1d1bSDag-Erling Smørgrav if (intptr != NULL) 152647dd1d1bSDag-Erling Smørgrav *intptr = *intptr + 1; 152747dd1d1bSDag-Erling Smørgrav } 152847dd1d1bSDag-Erling Smørgrav break; 1529511b41d2SMark Murray 153019261079SEd Maste case sModuliFile: 153119261079SEd Maste charptr = &options->moduli_file; 153219261079SEd Maste goto parse_filename; 153319261079SEd Maste 1534511b41d2SMark Murray case sPermitRootLogin: 1535511b41d2SMark Murray intptr = &options->permit_root_login; 1536e146993eSDag-Erling Smørgrav multistate_ptr = multistate_permitrootlogin; 1537e146993eSDag-Erling Smørgrav goto parse_multistate; 1538511b41d2SMark Murray 1539511b41d2SMark Murray case sIgnoreRhosts: 1540511b41d2SMark Murray intptr = &options->ignore_rhosts; 154119261079SEd Maste multistate_ptr = multistate_ignore_rhosts; 154247dd1d1bSDag-Erling Smørgrav goto parse_multistate; 1543511b41d2SMark Murray 1544511b41d2SMark Murray case sIgnoreUserKnownHosts: 1545511b41d2SMark Murray intptr = &options->ignore_user_known_hosts; 154619261079SEd Maste parse_flag: 154719261079SEd Maste multistate_ptr = multistate_flag; 154819261079SEd Maste goto parse_multistate; 1549511b41d2SMark Murray 1550ca3176e7SBrian Feldman case sHostbasedAuthentication: 1551ca3176e7SBrian Feldman intptr = &options->hostbased_authentication; 1552ca3176e7SBrian Feldman goto parse_flag; 1553ca3176e7SBrian Feldman 1554ca3176e7SBrian Feldman case sHostbasedUsesNameFromPacketOnly: 1555ca3176e7SBrian Feldman intptr = &options->hostbased_uses_name_from_packet_only; 1556ca3176e7SBrian Feldman goto parse_flag; 1557ca3176e7SBrian Feldman 155819261079SEd Maste case sHostbasedAcceptedAlgorithms: 155919261079SEd Maste charptr = &options->hostbased_accepted_algos; 1560535af610SEd Maste ca_only = 0; 156119261079SEd Maste parse_pubkey_algos: 156219261079SEd Maste arg = argv_next(&ac, &av); 1563bc5531deSDag-Erling Smørgrav if (!arg || *arg == '\0') 1564bc5531deSDag-Erling Smørgrav fatal("%s line %d: Missing argument.", 1565bc5531deSDag-Erling Smørgrav filename, linenum); 1566d93a896eSDag-Erling Smørgrav if (*arg != '-' && 156719261079SEd Maste !sshkey_names_valid2(*arg == '+' || *arg == '^' ? 1568535af610SEd Maste arg + 1 : arg, 1, ca_only)) 1569bc5531deSDag-Erling Smørgrav fatal("%s line %d: Bad key types '%s'.", 1570bc5531deSDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>"); 1571bc5531deSDag-Erling Smørgrav if (*activep && *charptr == NULL) 1572bc5531deSDag-Erling Smørgrav *charptr = xstrdup(arg); 1573bc5531deSDag-Erling Smørgrav break; 1574bc5531deSDag-Erling Smørgrav 1575eccfee6eSDag-Erling Smørgrav case sHostKeyAlgorithms: 1576eccfee6eSDag-Erling Smørgrav charptr = &options->hostkeyalgorithms; 1577535af610SEd Maste ca_only = 0; 157819261079SEd Maste goto parse_pubkey_algos; 1579eccfee6eSDag-Erling Smørgrav 15802f513db7SEd Maste case sCASignatureAlgorithms: 15812f513db7SEd Maste charptr = &options->ca_sign_algorithms; 1582535af610SEd Maste ca_only = 1; 158319261079SEd Maste goto parse_pubkey_algos; 15842f513db7SEd Maste 1585ca3176e7SBrian Feldman case sPubkeyAuthentication: 1586ca3176e7SBrian Feldman intptr = &options->pubkey_authentication; 1587535af610SEd Maste ca_only = 0; 1588e8aafc91SKris Kennaway goto parse_flag; 1589cf2b5f3bSDag-Erling Smørgrav 159019261079SEd Maste case sPubkeyAcceptedAlgorithms: 159119261079SEd Maste charptr = &options->pubkey_accepted_algos; 1592535af610SEd Maste ca_only = 0; 159319261079SEd Maste goto parse_pubkey_algos; 159419261079SEd Maste 159519261079SEd Maste case sPubkeyAuthOptions: 159619261079SEd Maste intptr = &options->pubkey_auth_options; 159719261079SEd Maste value = 0; 159819261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 159919261079SEd Maste if (strcasecmp(arg, "none") == 0) 160019261079SEd Maste continue; 160119261079SEd Maste if (strcasecmp(arg, "touch-required") == 0) 160219261079SEd Maste value |= PUBKEYAUTH_TOUCH_REQUIRED; 160319261079SEd Maste else if (strcasecmp(arg, "verify-required") == 0) 160419261079SEd Maste value |= PUBKEYAUTH_VERIFY_REQUIRED; 160519261079SEd Maste else { 160619261079SEd Maste error("%s line %d: unsupported %s option %s", 160719261079SEd Maste filename, linenum, keyword, arg); 160819261079SEd Maste goto out; 160919261079SEd Maste } 161019261079SEd Maste } 161119261079SEd Maste if (*activep && *intptr == -1) 161219261079SEd Maste *intptr = value; 161319261079SEd Maste break; 1614bc5531deSDag-Erling Smørgrav 1615cb96ab36SAssar Westerlund case sKerberosAuthentication: 1616cb96ab36SAssar Westerlund intptr = &options->kerberos_authentication; 1617511b41d2SMark Murray goto parse_flag; 1618511b41d2SMark Murray 1619af12a3e7SDag-Erling Smørgrav case sKerberosOrLocalPasswd: 1620af12a3e7SDag-Erling Smørgrav intptr = &options->kerberos_or_local_passwd; 1621511b41d2SMark Murray goto parse_flag; 1622511b41d2SMark Murray 1623af12a3e7SDag-Erling Smørgrav case sKerberosTicketCleanup: 1624af12a3e7SDag-Erling Smørgrav intptr = &options->kerberos_ticket_cleanup; 1625511b41d2SMark Murray goto parse_flag; 1626cf2b5f3bSDag-Erling Smørgrav 16271ec0d754SDag-Erling Smørgrav case sKerberosGetAFSToken: 16281ec0d754SDag-Erling Smørgrav intptr = &options->kerberos_get_afs_token; 16291ec0d754SDag-Erling Smørgrav goto parse_flag; 16301ec0d754SDag-Erling Smørgrav 1631cf2b5f3bSDag-Erling Smørgrav case sGssAuthentication: 1632cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_authentication; 1633fe5fd017SMark Murray goto parse_flag; 1634cf2b5f3bSDag-Erling Smørgrav 1635cf2b5f3bSDag-Erling Smørgrav case sGssCleanupCreds: 1636cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_cleanup_creds; 1637511b41d2SMark Murray goto parse_flag; 1638511b41d2SMark Murray 1639557f75e5SDag-Erling Smørgrav case sGssStrictAcceptor: 1640557f75e5SDag-Erling Smørgrav intptr = &options->gss_strict_acceptor; 1641557f75e5SDag-Erling Smørgrav goto parse_flag; 1642557f75e5SDag-Erling Smørgrav 1643511b41d2SMark Murray case sPasswordAuthentication: 1644511b41d2SMark Murray intptr = &options->password_authentication; 1645511b41d2SMark Murray goto parse_flag; 1646511b41d2SMark Murray 164709958426SBrian Feldman case sKbdInteractiveAuthentication: 164809958426SBrian Feldman intptr = &options->kbd_interactive_authentication; 164909958426SBrian Feldman goto parse_flag; 165009958426SBrian Feldman 1651511b41d2SMark Murray case sPrintMotd: 1652511b41d2SMark Murray intptr = &options->print_motd; 1653511b41d2SMark Murray goto parse_flag; 1654511b41d2SMark Murray 1655ca3176e7SBrian Feldman case sPrintLastLog: 1656ca3176e7SBrian Feldman intptr = &options->print_lastlog; 1657ca3176e7SBrian Feldman goto parse_flag; 1658ca3176e7SBrian Feldman 1659511b41d2SMark Murray case sX11Forwarding: 1660511b41d2SMark Murray intptr = &options->x11_forwarding; 1661511b41d2SMark Murray goto parse_flag; 1662511b41d2SMark Murray 1663511b41d2SMark Murray case sX11DisplayOffset: 1664511b41d2SMark Murray intptr = &options->x11_display_offset; 1665ca86bcf2SDag-Erling Smørgrav parse_int: 166619261079SEd Maste arg = argv_next(&ac, &av); 166747dd1d1bSDag-Erling Smørgrav if ((errstr = atoi_err(arg, &value)) != NULL) 166819261079SEd Maste fatal("%s line %d: %s integer value %s.", 166919261079SEd Maste filename, linenum, keyword, errstr); 1670ca86bcf2SDag-Erling Smørgrav if (*activep && *intptr == -1) 1671ca86bcf2SDag-Erling Smørgrav *intptr = value; 1672ca86bcf2SDag-Erling Smørgrav break; 1673511b41d2SMark Murray 1674af12a3e7SDag-Erling Smørgrav case sX11UseLocalhost: 1675af12a3e7SDag-Erling Smørgrav intptr = &options->x11_use_localhost; 1676af12a3e7SDag-Erling Smørgrav goto parse_flag; 1677af12a3e7SDag-Erling Smørgrav 1678c2d3a559SKris Kennaway case sXAuthLocation: 1679c2d3a559SKris Kennaway charptr = &options->xauth_location; 1680c2d3a559SKris Kennaway goto parse_filename; 1681c2d3a559SKris Kennaway 1682f7167e0eSDag-Erling Smørgrav case sPermitTTY: 1683f7167e0eSDag-Erling Smørgrav intptr = &options->permit_tty; 1684f7167e0eSDag-Erling Smørgrav goto parse_flag; 1685f7167e0eSDag-Erling Smørgrav 1686a0ee8cc6SDag-Erling Smørgrav case sPermitUserRC: 1687a0ee8cc6SDag-Erling Smørgrav intptr = &options->permit_user_rc; 1688a0ee8cc6SDag-Erling Smørgrav goto parse_flag; 1689a0ee8cc6SDag-Erling Smørgrav 1690511b41d2SMark Murray case sStrictModes: 1691511b41d2SMark Murray intptr = &options->strict_modes; 1692511b41d2SMark Murray goto parse_flag; 1693511b41d2SMark Murray 16941ec0d754SDag-Erling Smørgrav case sTCPKeepAlive: 16951ec0d754SDag-Erling Smørgrav intptr = &options->tcp_keep_alive; 1696511b41d2SMark Murray goto parse_flag; 1697511b41d2SMark Murray 1698511b41d2SMark Murray case sEmptyPasswd: 1699511b41d2SMark Murray intptr = &options->permit_empty_passwd; 1700511b41d2SMark Murray goto parse_flag; 1701511b41d2SMark Murray 1702f388f5efSDag-Erling Smørgrav case sPermitUserEnvironment: 1703f388f5efSDag-Erling Smørgrav intptr = &options->permit_user_env; 170419261079SEd Maste charptr = &options->permit_user_env_allowlist; 170519261079SEd Maste arg = argv_next(&ac, &av); 1706190cef3dSDag-Erling Smørgrav if (!arg || *arg == '\0') 170719261079SEd Maste fatal("%s line %d: %s missing argument.", 170819261079SEd Maste filename, linenum, keyword); 1709190cef3dSDag-Erling Smørgrav value = 0; 1710190cef3dSDag-Erling Smørgrav p = NULL; 1711190cef3dSDag-Erling Smørgrav if (strcmp(arg, "yes") == 0) 1712190cef3dSDag-Erling Smørgrav value = 1; 1713190cef3dSDag-Erling Smørgrav else if (strcmp(arg, "no") == 0) 1714190cef3dSDag-Erling Smørgrav value = 0; 1715190cef3dSDag-Erling Smørgrav else { 1716190cef3dSDag-Erling Smørgrav /* Pattern-list specified */ 1717190cef3dSDag-Erling Smørgrav value = 1; 1718190cef3dSDag-Erling Smørgrav p = xstrdup(arg); 1719190cef3dSDag-Erling Smørgrav } 1720190cef3dSDag-Erling Smørgrav if (*activep && *intptr == -1) { 1721190cef3dSDag-Erling Smørgrav *intptr = value; 1722190cef3dSDag-Erling Smørgrav *charptr = p; 1723190cef3dSDag-Erling Smørgrav p = NULL; 1724190cef3dSDag-Erling Smørgrav } 1725190cef3dSDag-Erling Smørgrav free(p); 1726190cef3dSDag-Erling Smørgrav break; 1727f388f5efSDag-Erling Smørgrav 172880628bacSDag-Erling Smørgrav case sCompression: 172980628bacSDag-Erling Smørgrav intptr = &options->compression; 1730e146993eSDag-Erling Smørgrav multistate_ptr = multistate_compression; 1731e146993eSDag-Erling Smørgrav goto parse_multistate; 173280628bacSDag-Erling Smørgrav 1733e4a9863fSDag-Erling Smørgrav case sRekeyLimit: 173419261079SEd Maste arg = argv_next(&ac, &av); 1735e4a9863fSDag-Erling Smørgrav if (!arg || *arg == '\0') 173619261079SEd Maste fatal("%s line %d: %s missing argument.", 173719261079SEd Maste filename, linenum, keyword); 1738e4a9863fSDag-Erling Smørgrav if (strcmp(arg, "default") == 0) { 1739e4a9863fSDag-Erling Smørgrav val64 = 0; 1740e4a9863fSDag-Erling Smørgrav } else { 1741e4a9863fSDag-Erling Smørgrav if (scan_scaled(arg, &val64) == -1) 174219261079SEd Maste fatal("%.200s line %d: Bad %s number '%s': %s", 174319261079SEd Maste filename, linenum, keyword, 174419261079SEd Maste arg, strerror(errno)); 1745e4a9863fSDag-Erling Smørgrav if (val64 != 0 && val64 < 16) 174619261079SEd Maste fatal("%.200s line %d: %s too small", 174719261079SEd Maste filename, linenum, keyword); 1748e4a9863fSDag-Erling Smørgrav } 1749e4a9863fSDag-Erling Smørgrav if (*activep && options->rekey_limit == -1) 1750acc1a9efSDag-Erling Smørgrav options->rekey_limit = val64; 175119261079SEd Maste if (ac != 0) { /* optional rekey interval present */ 175219261079SEd Maste if (strcmp(av[0], "none") == 0) { 175319261079SEd Maste (void)argv_next(&ac, &av); /* discard */ 1754e4a9863fSDag-Erling Smørgrav break; 1755e4a9863fSDag-Erling Smørgrav } 1756e4a9863fSDag-Erling Smørgrav intptr = &options->rekey_interval; 1757e4a9863fSDag-Erling Smørgrav goto parse_time; 1758e4a9863fSDag-Erling Smørgrav } 1759e4a9863fSDag-Erling Smørgrav break; 1760e4a9863fSDag-Erling Smørgrav 1761e8aafc91SKris Kennaway case sGatewayPorts: 1762a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.gateway_ports; 1763e146993eSDag-Erling Smørgrav multistate_ptr = multistate_gatewayports; 1764e146993eSDag-Erling Smørgrav goto parse_multistate; 1765e8aafc91SKris Kennaway 1766cf2b5f3bSDag-Erling Smørgrav case sUseDNS: 1767cf2b5f3bSDag-Erling Smørgrav intptr = &options->use_dns; 1768ca3176e7SBrian Feldman goto parse_flag; 1769ca3176e7SBrian Feldman 1770511b41d2SMark Murray case sLogFacility: 1771d4af9e69SDag-Erling Smørgrav log_facility_ptr = &options->log_facility; 177219261079SEd Maste arg = argv_next(&ac, &av); 1773c2d3a559SKris Kennaway value = log_facility_number(arg); 1774af12a3e7SDag-Erling Smørgrav if (value == SYSLOG_FACILITY_NOT_SET) 1775ca3176e7SBrian Feldman fatal("%.200s line %d: unsupported log facility '%s'", 1776c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 1777d4af9e69SDag-Erling Smørgrav if (*log_facility_ptr == -1) 1778d4af9e69SDag-Erling Smørgrav *log_facility_ptr = (SyslogFacility) value; 1779511b41d2SMark Murray break; 1780511b41d2SMark Murray 1781511b41d2SMark Murray case sLogLevel: 1782d4af9e69SDag-Erling Smørgrav log_level_ptr = &options->log_level; 178319261079SEd Maste arg = argv_next(&ac, &av); 1784c2d3a559SKris Kennaway value = log_level_number(arg); 1785af12a3e7SDag-Erling Smørgrav if (value == SYSLOG_LEVEL_NOT_SET) 1786ca3176e7SBrian Feldman fatal("%.200s line %d: unsupported log level '%s'", 1787c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 17884f52dfbbSDag-Erling Smørgrav if (*activep && *log_level_ptr == -1) 1789d4af9e69SDag-Erling Smørgrav *log_level_ptr = (LogLevel) value; 1790511b41d2SMark Murray break; 1791511b41d2SMark Murray 179219261079SEd Maste case sLogVerbose: 179319261079SEd Maste found = options->num_log_verbose == 0; 179419261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 179519261079SEd Maste if (*arg == '\0') { 179619261079SEd Maste error("%s line %d: keyword %s empty argument", 179719261079SEd Maste filename, linenum, keyword); 179819261079SEd Maste goto out; 179919261079SEd Maste } 180019261079SEd Maste /* Allow "none" only in first position */ 180119261079SEd Maste if (strcasecmp(arg, "none") == 0) { 1802*a91a2465SEd Maste if (nstrs > 0 || ac > 0) { 180319261079SEd Maste error("%s line %d: keyword %s \"none\" " 180419261079SEd Maste "argument must appear alone.", 180519261079SEd Maste filename, linenum, keyword); 180619261079SEd Maste goto out; 180719261079SEd Maste } 180819261079SEd Maste } 180919261079SEd Maste opt_array_append(filename, linenum, keyword, 1810*a91a2465SEd Maste &strs, &nstrs, arg); 1811*a91a2465SEd Maste } 1812*a91a2465SEd Maste if (nstrs == 0) { 1813*a91a2465SEd Maste fatal("%s line %d: no %s specified", 1814*a91a2465SEd Maste filename, linenum, keyword); 1815*a91a2465SEd Maste } 1816*a91a2465SEd Maste if (found && *activep) { 1817*a91a2465SEd Maste options->log_verbose = strs; 1818*a91a2465SEd Maste options->num_log_verbose = nstrs; 1819*a91a2465SEd Maste strs = NULL; /* transferred */ 1820*a91a2465SEd Maste nstrs = 0; 182119261079SEd Maste } 182219261079SEd Maste break; 182319261079SEd Maste 182409958426SBrian Feldman case sAllowTcpForwarding: 182509958426SBrian Feldman intptr = &options->allow_tcp_forwarding; 18266888a9beSDag-Erling Smørgrav multistate_ptr = multistate_tcpfwd; 18276888a9beSDag-Erling Smørgrav goto parse_multistate; 182809958426SBrian Feldman 1829a0ee8cc6SDag-Erling Smørgrav case sAllowStreamLocalForwarding: 1830a0ee8cc6SDag-Erling Smørgrav intptr = &options->allow_streamlocal_forwarding; 1831a0ee8cc6SDag-Erling Smørgrav multistate_ptr = multistate_tcpfwd; 1832a0ee8cc6SDag-Erling Smørgrav goto parse_multistate; 1833a0ee8cc6SDag-Erling Smørgrav 1834d4af9e69SDag-Erling Smørgrav case sAllowAgentForwarding: 1835d4af9e69SDag-Erling Smørgrav intptr = &options->allow_agent_forwarding; 1836d4af9e69SDag-Erling Smørgrav goto parse_flag; 1837d4af9e69SDag-Erling Smørgrav 1838ca86bcf2SDag-Erling Smørgrav case sDisableForwarding: 1839ca86bcf2SDag-Erling Smørgrav intptr = &options->disable_forwarding; 1840ca86bcf2SDag-Erling Smørgrav goto parse_flag; 1841ca86bcf2SDag-Erling Smørgrav 1842511b41d2SMark Murray case sAllowUsers: 184319261079SEd Maste chararrayptr = &options->allow_users; 184419261079SEd Maste uintptr = &options->num_allow_users; 184519261079SEd Maste parse_allowdenyusers: 1846*a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */ 184719261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 184819261079SEd Maste if (*arg == '\0' || 184919261079SEd Maste match_user(NULL, NULL, NULL, arg) == -1) 185019261079SEd Maste fatal("%s line %d: invalid %s pattern: \"%s\"", 185119261079SEd Maste filename, linenum, keyword, arg); 1852*a91a2465SEd Maste found = 1; 1853462c32cbSDag-Erling Smørgrav if (!*activep) 1854462c32cbSDag-Erling Smørgrav continue; 185519261079SEd Maste opt_array_append(filename, linenum, keyword, 185619261079SEd Maste chararrayptr, uintptr, arg); 1857511b41d2SMark Murray } 1858*a91a2465SEd Maste if (!found) { 1859*a91a2465SEd Maste fatal("%s line %d: no %s specified", 1860*a91a2465SEd Maste filename, linenum, keyword); 1861*a91a2465SEd Maste } 1862511b41d2SMark Murray break; 1863511b41d2SMark Murray 1864511b41d2SMark Murray case sDenyUsers: 186519261079SEd Maste chararrayptr = &options->deny_users; 186619261079SEd Maste uintptr = &options->num_deny_users; 186719261079SEd Maste goto parse_allowdenyusers; 1868511b41d2SMark Murray 1869511b41d2SMark Murray case sAllowGroups: 187019261079SEd Maste chararrayptr = &options->allow_groups; 187119261079SEd Maste uintptr = &options->num_allow_groups; 1872*a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */ 187319261079SEd Maste parse_allowdenygroups: 187419261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 187519261079SEd Maste if (*arg == '\0') 187619261079SEd Maste fatal("%s line %d: empty %s pattern", 187719261079SEd Maste filename, linenum, keyword); 1878*a91a2465SEd Maste found = 1; 1879462c32cbSDag-Erling Smørgrav if (!*activep) 1880462c32cbSDag-Erling Smørgrav continue; 188119261079SEd Maste opt_array_append(filename, linenum, keyword, 188219261079SEd Maste chararrayptr, uintptr, arg); 1883511b41d2SMark Murray } 1884*a91a2465SEd Maste if (!found) { 1885*a91a2465SEd Maste fatal("%s line %d: no %s specified", 1886*a91a2465SEd Maste filename, linenum, keyword); 1887*a91a2465SEd Maste } 1888511b41d2SMark Murray break; 1889511b41d2SMark Murray 1890511b41d2SMark Murray case sDenyGroups: 189119261079SEd Maste chararrayptr = &options->deny_groups; 189219261079SEd Maste uintptr = &options->num_deny_groups; 189319261079SEd Maste goto parse_allowdenygroups; 1894511b41d2SMark Murray 1895e8aafc91SKris Kennaway case sCiphers: 189619261079SEd Maste arg = argv_next(&ac, &av); 1897c2d3a559SKris Kennaway if (!arg || *arg == '\0') 189819261079SEd Maste fatal("%s line %d: %s missing argument.", 189919261079SEd Maste filename, linenum, keyword); 190019261079SEd Maste if (*arg != '-' && 190119261079SEd Maste !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) 1902e8aafc91SKris Kennaway fatal("%s line %d: Bad SSH2 cipher spec '%s'.", 1903c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 1904e8aafc91SKris Kennaway if (options->ciphers == NULL) 1905c2d3a559SKris Kennaway options->ciphers = xstrdup(arg); 1906e8aafc91SKris Kennaway break; 1907e8aafc91SKris Kennaway 1908ca3176e7SBrian Feldman case sMacs: 190919261079SEd Maste arg = argv_next(&ac, &av); 1910ca3176e7SBrian Feldman if (!arg || *arg == '\0') 191119261079SEd Maste fatal("%s line %d: %s missing argument.", 191219261079SEd Maste filename, linenum, keyword); 191319261079SEd Maste if (*arg != '-' && 191419261079SEd Maste !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) 1915ca3176e7SBrian Feldman fatal("%s line %d: Bad SSH2 mac spec '%s'.", 1916ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>"); 1917ca3176e7SBrian Feldman if (options->macs == NULL) 1918ca3176e7SBrian Feldman options->macs = xstrdup(arg); 1919ca3176e7SBrian Feldman break; 1920ca3176e7SBrian Feldman 19214a421b63SDag-Erling Smørgrav case sKexAlgorithms: 192219261079SEd Maste arg = argv_next(&ac, &av); 19234a421b63SDag-Erling Smørgrav if (!arg || *arg == '\0') 192419261079SEd Maste fatal("%s line %d: %s missing argument.", 192519261079SEd Maste filename, linenum, keyword); 1926d93a896eSDag-Erling Smørgrav if (*arg != '-' && 192719261079SEd Maste !kex_names_valid(*arg == '+' || *arg == '^' ? 192819261079SEd Maste arg + 1 : arg)) 19294a421b63SDag-Erling Smørgrav fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.", 19304a421b63SDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>"); 19314a421b63SDag-Erling Smørgrav if (options->kex_algorithms == NULL) 19324a421b63SDag-Erling Smørgrav options->kex_algorithms = xstrdup(arg); 19334a421b63SDag-Erling Smørgrav break; 19344a421b63SDag-Erling Smørgrav 1935c2d3a559SKris Kennaway case sSubsystem: 193619261079SEd Maste arg = argv_next(&ac, &av); 1937c2d3a559SKris Kennaway if (!arg || *arg == '\0') 193819261079SEd Maste fatal("%s line %d: %s missing argument.", 193919261079SEd Maste filename, linenum, keyword); 1940333ee039SDag-Erling Smørgrav if (!*activep) { 1941edf85781SEd Maste argv_consume(&ac); 1942333ee039SDag-Erling Smørgrav break; 1943333ee039SDag-Erling Smørgrav } 1944edf85781SEd Maste found = 0; 1945edf85781SEd Maste for (i = 0; i < options->num_subsystems; i++) { 1946edf85781SEd Maste if (strcmp(arg, options->subsystem_name[i]) == 0) { 1947edf85781SEd Maste found = 1; 1948edf85781SEd Maste break; 1949edf85781SEd Maste } 1950edf85781SEd Maste } 1951edf85781SEd Maste if (found) { 1952edf85781SEd Maste debug("%s line %d: Subsystem '%s' already defined.", 1953edf85781SEd Maste filename, linenum, arg); 1954edf85781SEd Maste argv_consume(&ac); 1955edf85781SEd Maste break; 1956edf85781SEd Maste } 1957edf85781SEd Maste options->subsystem_name = xrecallocarray( 1958edf85781SEd Maste options->subsystem_name, options->num_subsystems, 1959edf85781SEd Maste options->num_subsystems + 1, 1960edf85781SEd Maste sizeof(*options->subsystem_name)); 1961edf85781SEd Maste options->subsystem_command = xrecallocarray( 1962edf85781SEd Maste options->subsystem_command, options->num_subsystems, 1963edf85781SEd Maste options->num_subsystems + 1, 1964edf85781SEd Maste sizeof(*options->subsystem_command)); 1965edf85781SEd Maste options->subsystem_args = xrecallocarray( 1966edf85781SEd Maste options->subsystem_args, options->num_subsystems, 1967edf85781SEd Maste options->num_subsystems + 1, 1968edf85781SEd Maste sizeof(*options->subsystem_args)); 1969c2d3a559SKris Kennaway options->subsystem_name[options->num_subsystems] = xstrdup(arg); 197019261079SEd Maste arg = argv_next(&ac, &av); 1971edf85781SEd Maste if (!arg || *arg == '\0') { 1972c2d3a559SKris Kennaway fatal("%s line %d: Missing subsystem command.", 1973c2d3a559SKris Kennaway filename, linenum); 1974333ee039SDag-Erling Smørgrav } 1975edf85781SEd Maste options->subsystem_command[options->num_subsystems] = 1976edf85781SEd Maste xstrdup(arg); 1977edf85781SEd Maste /* Collect arguments (separate to executable) */ 1978edf85781SEd Maste arg = argv_assemble(1, &arg); /* quote command correctly */ 1979edf85781SEd Maste arg2 = argv_assemble(ac, av); /* rest of command */ 1980edf85781SEd Maste xasprintf(&options->subsystem_args[options->num_subsystems], 1981*a91a2465SEd Maste "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2); 1982edf85781SEd Maste free(arg2); 1983edf85781SEd Maste argv_consume(&ac); 1984c2d3a559SKris Kennaway options->num_subsystems++; 1985c2d3a559SKris Kennaway break; 1986c2d3a559SKris Kennaway 1987c2d3a559SKris Kennaway case sMaxStartups: 198819261079SEd Maste arg = argv_next(&ac, &av); 1989c2d3a559SKris Kennaway if (!arg || *arg == '\0') 199019261079SEd Maste fatal("%s line %d: %s missing argument.", 199119261079SEd Maste filename, linenum, keyword); 1992af12a3e7SDag-Erling Smørgrav if ((n = sscanf(arg, "%d:%d:%d", 1993c2d3a559SKris Kennaway &options->max_startups_begin, 1994c2d3a559SKris Kennaway &options->max_startups_rate, 1995af12a3e7SDag-Erling Smørgrav &options->max_startups)) == 3) { 1996c2d3a559SKris Kennaway if (options->max_startups_begin > 1997c2d3a559SKris Kennaway options->max_startups || 1998c2d3a559SKris Kennaway options->max_startups_rate > 100 || 1999c2d3a559SKris Kennaway options->max_startups_rate < 1) 200019261079SEd Maste fatal("%s line %d: Invalid %s spec.", 200119261079SEd Maste filename, linenum, keyword); 2002af12a3e7SDag-Erling Smørgrav } else if (n != 1) 200319261079SEd Maste fatal("%s line %d: Invalid %s spec.", 200419261079SEd Maste filename, linenum, keyword); 2005af12a3e7SDag-Erling Smørgrav else 2006af12a3e7SDag-Erling Smørgrav options->max_startups = options->max_startups_begin; 2007f374ba41SEd Maste if (options->max_startups <= 0 || 2008f374ba41SEd Maste options->max_startups_begin <= 0) 2009f374ba41SEd Maste fatal("%s line %d: Invalid %s spec.", 2010f374ba41SEd Maste filename, linenum, keyword); 2011933ca70fSBrian Feldman break; 2012933ca70fSBrian Feldman 201319261079SEd Maste case sPerSourceNetBlockSize: 201419261079SEd Maste arg = argv_next(&ac, &av); 201519261079SEd Maste if (!arg || *arg == '\0') 201619261079SEd Maste fatal("%s line %d: %s missing argument.", 201719261079SEd Maste filename, linenum, keyword); 201819261079SEd Maste switch (n = sscanf(arg, "%d:%d", &value, &value2)) { 201919261079SEd Maste case 2: 202019261079SEd Maste if (value2 < 0 || value2 > 128) 202119261079SEd Maste n = -1; 202219261079SEd Maste /* FALLTHROUGH */ 202319261079SEd Maste case 1: 202419261079SEd Maste if (value < 0 || value > 32) 202519261079SEd Maste n = -1; 202619261079SEd Maste } 202719261079SEd Maste if (n != 1 && n != 2) 202819261079SEd Maste fatal("%s line %d: Invalid %s spec.", 202919261079SEd Maste filename, linenum, keyword); 203019261079SEd Maste if (*activep) { 203119261079SEd Maste options->per_source_masklen_ipv4 = value; 203219261079SEd Maste options->per_source_masklen_ipv6 = value2; 203319261079SEd Maste } 203419261079SEd Maste break; 203519261079SEd Maste 203619261079SEd Maste case sPerSourceMaxStartups: 203719261079SEd Maste arg = argv_next(&ac, &av); 203819261079SEd Maste if (!arg || *arg == '\0') 203919261079SEd Maste fatal("%s line %d: %s missing argument.", 204019261079SEd Maste filename, linenum, keyword); 204119261079SEd Maste if (strcmp(arg, "none") == 0) { /* no limit */ 204219261079SEd Maste value = INT_MAX; 204319261079SEd Maste } else { 204419261079SEd Maste if ((errstr = atoi_err(arg, &value)) != NULL) 204519261079SEd Maste fatal("%s line %d: %s integer value %s.", 204619261079SEd Maste filename, linenum, keyword, errstr); 204719261079SEd Maste } 2048edf85781SEd Maste if (*activep && options->per_source_max_startups == -1) 204919261079SEd Maste options->per_source_max_startups = value; 205019261079SEd Maste break; 205119261079SEd Maste 205221e764dfSDag-Erling Smørgrav case sMaxAuthTries: 205321e764dfSDag-Erling Smørgrav intptr = &options->max_authtries; 205421e764dfSDag-Erling Smørgrav goto parse_int; 205521e764dfSDag-Erling Smørgrav 2056d4af9e69SDag-Erling Smørgrav case sMaxSessions: 2057d4af9e69SDag-Erling Smørgrav intptr = &options->max_sessions; 2058d4af9e69SDag-Erling Smørgrav goto parse_int; 2059d4af9e69SDag-Erling Smørgrav 2060ca3176e7SBrian Feldman case sBanner: 2061ca3176e7SBrian Feldman charptr = &options->banner; 2062ca3176e7SBrian Feldman goto parse_filename; 2063d4af9e69SDag-Erling Smørgrav 2064af12a3e7SDag-Erling Smørgrav /* 2065af12a3e7SDag-Erling Smørgrav * These options can contain %X options expanded at 2066af12a3e7SDag-Erling Smørgrav * connect time, so that you can specify paths like: 2067af12a3e7SDag-Erling Smørgrav * 2068af12a3e7SDag-Erling Smørgrav * AuthorizedKeysFile /etc/ssh_keys/%u 2069af12a3e7SDag-Erling Smørgrav */ 2070af12a3e7SDag-Erling Smørgrav case sAuthorizedKeysFile: 2071*a91a2465SEd Maste found = options->num_authkeys_files == 0; 207219261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 207319261079SEd Maste if (*arg == '\0') { 207419261079SEd Maste error("%s line %d: keyword %s empty argument", 207519261079SEd Maste filename, linenum, keyword); 207619261079SEd Maste goto out; 207719261079SEd Maste } 207819261079SEd Maste arg2 = tilde_expand_filename(arg, getuid()); 207919261079SEd Maste opt_array_append(filename, linenum, keyword, 2080*a91a2465SEd Maste &strs, &nstrs, arg2); 208119261079SEd Maste free(arg2); 2082e146993eSDag-Erling Smørgrav } 2083*a91a2465SEd Maste if (nstrs == 0) { 2084*a91a2465SEd Maste fatal("%s line %d: no %s specified", 2085*a91a2465SEd Maste filename, linenum, keyword); 2086*a91a2465SEd Maste } 2087*a91a2465SEd Maste if (found && *activep) { 2088*a91a2465SEd Maste options->authorized_keys_files = strs; 2089*a91a2465SEd Maste options->num_authkeys_files = nstrs; 2090*a91a2465SEd Maste strs = NULL; /* transferred */ 2091*a91a2465SEd Maste nstrs = 0; 2092*a91a2465SEd Maste } 209319261079SEd Maste break; 2094e146993eSDag-Erling Smørgrav 2095e2f6069cSDag-Erling Smørgrav case sAuthorizedPrincipalsFile: 2096e2f6069cSDag-Erling Smørgrav charptr = &options->authorized_principals_file; 209719261079SEd Maste arg = argv_next(&ac, &av); 20988ad9b54aSDag-Erling Smørgrav if (!arg || *arg == '\0') 209919261079SEd Maste fatal("%s line %d: %s missing argument.", 210019261079SEd Maste filename, linenum, keyword); 21018ad9b54aSDag-Erling Smørgrav if (*activep && *charptr == NULL) { 21028ad9b54aSDag-Erling Smørgrav *charptr = tilde_expand_filename(arg, getuid()); 21038ad9b54aSDag-Erling Smørgrav /* increase optional counter */ 21048ad9b54aSDag-Erling Smørgrav if (intptr != NULL) 21058ad9b54aSDag-Erling Smørgrav *intptr = *intptr + 1; 21068ad9b54aSDag-Erling Smørgrav } 21078ad9b54aSDag-Erling Smørgrav break; 2108af12a3e7SDag-Erling Smørgrav 2109ca3176e7SBrian Feldman case sClientAliveInterval: 2110ca3176e7SBrian Feldman intptr = &options->client_alive_interval; 2111af12a3e7SDag-Erling Smørgrav goto parse_time; 2112af12a3e7SDag-Erling Smørgrav 2113ca3176e7SBrian Feldman case sClientAliveCountMax: 2114ca3176e7SBrian Feldman intptr = &options->client_alive_count_max; 2115ca3176e7SBrian Feldman goto parse_int; 2116af12a3e7SDag-Erling Smørgrav 211721e764dfSDag-Erling Smørgrav case sAcceptEnv: 2118*a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */ 211919261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 212019261079SEd Maste if (*arg == '\0' || strchr(arg, '=') != NULL) 212121e764dfSDag-Erling Smørgrav fatal("%s line %d: Invalid environment name.", 212221e764dfSDag-Erling Smørgrav filename, linenum); 2123*a91a2465SEd Maste found = 1; 2124333ee039SDag-Erling Smørgrav if (!*activep) 2125462c32cbSDag-Erling Smørgrav continue; 212619261079SEd Maste opt_array_append(filename, linenum, keyword, 212747dd1d1bSDag-Erling Smørgrav &options->accept_env, &options->num_accept_env, 212847dd1d1bSDag-Erling Smørgrav arg); 212921e764dfSDag-Erling Smørgrav } 2130*a91a2465SEd Maste if (!found) { 2131*a91a2465SEd Maste fatal("%s line %d: no %s specified", 2132*a91a2465SEd Maste filename, linenum, keyword); 2133*a91a2465SEd Maste } 213421e764dfSDag-Erling Smørgrav break; 213521e764dfSDag-Erling Smørgrav 2136190cef3dSDag-Erling Smørgrav case sSetEnv: 2137*a91a2465SEd Maste found = options->num_setenv == 0; 213819261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 213919261079SEd Maste if (*arg == '\0' || strchr(arg, '=') == NULL) 2140190cef3dSDag-Erling Smørgrav fatal("%s line %d: Invalid environment.", 2141190cef3dSDag-Erling Smørgrav filename, linenum); 2142*a91a2465SEd Maste if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) { 214338a52bd3SEd Maste debug2("%s line %d: ignoring duplicate env " 214438a52bd3SEd Maste "name \"%.64s\"", filename, linenum, arg); 214538a52bd3SEd Maste continue; 214638a52bd3SEd Maste } 214719261079SEd Maste opt_array_append(filename, linenum, keyword, 2148*a91a2465SEd Maste &strs, &nstrs, arg); 2149*a91a2465SEd Maste } 2150*a91a2465SEd Maste if (nstrs == 0) { 2151*a91a2465SEd Maste fatal("%s line %d: no %s specified", 2152*a91a2465SEd Maste filename, linenum, keyword); 2153*a91a2465SEd Maste } 2154*a91a2465SEd Maste if (found && *activep) { 2155*a91a2465SEd Maste options->setenv = strs; 2156*a91a2465SEd Maste options->num_setenv = nstrs; 2157*a91a2465SEd Maste strs = NULL; /* transferred */ 2158*a91a2465SEd Maste nstrs = 0; 2159190cef3dSDag-Erling Smørgrav } 2160190cef3dSDag-Erling Smørgrav break; 2161190cef3dSDag-Erling Smørgrav 2162b74df5b2SDag-Erling Smørgrav case sPermitTunnel: 2163b74df5b2SDag-Erling Smørgrav intptr = &options->permit_tun; 216419261079SEd Maste arg = argv_next(&ac, &av); 2165b74df5b2SDag-Erling Smørgrav if (!arg || *arg == '\0') 216619261079SEd Maste fatal("%s line %d: %s missing argument.", 216719261079SEd Maste filename, linenum, keyword); 2168d4af9e69SDag-Erling Smørgrav value = -1; 2169d4af9e69SDag-Erling Smørgrav for (i = 0; tunmode_desc[i].val != -1; i++) 2170d4af9e69SDag-Erling Smørgrav if (strcmp(tunmode_desc[i].text, arg) == 0) { 2171d4af9e69SDag-Erling Smørgrav value = tunmode_desc[i].val; 2172d4af9e69SDag-Erling Smørgrav break; 2173d4af9e69SDag-Erling Smørgrav } 2174d4af9e69SDag-Erling Smørgrav if (value == -1) 217519261079SEd Maste fatal("%s line %d: bad %s argument %s", 217619261079SEd Maste filename, linenum, keyword, arg); 2177557f75e5SDag-Erling Smørgrav if (*activep && *intptr == -1) 2178b74df5b2SDag-Erling Smørgrav *intptr = value; 2179b74df5b2SDag-Erling Smørgrav break; 2180b74df5b2SDag-Erling Smørgrav 218119261079SEd Maste case sInclude: 218219261079SEd Maste if (cmdline) { 218319261079SEd Maste fatal("Include directive not supported as a " 218419261079SEd Maste "command-line option"); 218519261079SEd Maste } 218619261079SEd Maste value = 0; 218719261079SEd Maste while ((arg2 = argv_next(&ac, &av)) != NULL) { 218819261079SEd Maste if (*arg2 == '\0') { 218919261079SEd Maste error("%s line %d: keyword %s empty argument", 219019261079SEd Maste filename, linenum, keyword); 219119261079SEd Maste goto out; 219219261079SEd Maste } 219319261079SEd Maste value++; 219419261079SEd Maste found = 0; 219519261079SEd Maste if (*arg2 != '/' && *arg2 != '~') { 219619261079SEd Maste xasprintf(&arg, "%s/%s", SSHDIR, arg2); 219719261079SEd Maste } else 219819261079SEd Maste arg = xstrdup(arg2); 219919261079SEd Maste 220019261079SEd Maste /* 220119261079SEd Maste * Don't let included files clobber the containing 220219261079SEd Maste * file's Match state. 220319261079SEd Maste */ 220419261079SEd Maste oactive = *activep; 220519261079SEd Maste 220619261079SEd Maste /* consult cache of include files */ 220719261079SEd Maste TAILQ_FOREACH(item, includes, entry) { 220819261079SEd Maste if (strcmp(item->selector, arg) != 0) 220919261079SEd Maste continue; 221019261079SEd Maste if (item->filename != NULL) { 221119261079SEd Maste parse_server_config_depth(options, 221219261079SEd Maste item->filename, item->contents, 221319261079SEd Maste includes, connectinfo, 221419261079SEd Maste (*inc_flags & SSHCFG_MATCH_ONLY 221519261079SEd Maste ? SSHCFG_MATCH_ONLY : (oactive 221619261079SEd Maste ? 0 : SSHCFG_NEVERMATCH)), 221719261079SEd Maste activep, depth + 1); 221819261079SEd Maste } 221919261079SEd Maste found = 1; 222019261079SEd Maste *activep = oactive; 222119261079SEd Maste } 222219261079SEd Maste if (found != 0) { 222319261079SEd Maste free(arg); 222419261079SEd Maste continue; 222519261079SEd Maste } 222619261079SEd Maste 222719261079SEd Maste /* requested glob was not in cache */ 222819261079SEd Maste debug2("%s line %d: new include %s", 222919261079SEd Maste filename, linenum, arg); 223019261079SEd Maste if ((r = glob(arg, 0, NULL, &gbuf)) != 0) { 223119261079SEd Maste if (r != GLOB_NOMATCH) { 223219261079SEd Maste fatal("%s line %d: include \"%s\" glob " 223319261079SEd Maste "failed", filename, linenum, arg); 223419261079SEd Maste } 223519261079SEd Maste /* 223619261079SEd Maste * If no entry matched then record a 223719261079SEd Maste * placeholder to skip later glob calls. 223819261079SEd Maste */ 223919261079SEd Maste debug2("%s line %d: no match for %s", 224019261079SEd Maste filename, linenum, arg); 224119261079SEd Maste item = xcalloc(1, sizeof(*item)); 224219261079SEd Maste item->selector = strdup(arg); 224319261079SEd Maste TAILQ_INSERT_TAIL(includes, 224419261079SEd Maste item, entry); 224519261079SEd Maste } 224619261079SEd Maste if (gbuf.gl_pathc > INT_MAX) 224719261079SEd Maste fatal_f("too many glob results"); 224819261079SEd Maste for (n = 0; n < (int)gbuf.gl_pathc; n++) { 224919261079SEd Maste debug2("%s line %d: including %s", 225019261079SEd Maste filename, linenum, gbuf.gl_pathv[n]); 225119261079SEd Maste item = xcalloc(1, sizeof(*item)); 225219261079SEd Maste item->selector = strdup(arg); 225319261079SEd Maste item->filename = strdup(gbuf.gl_pathv[n]); 225419261079SEd Maste if ((item->contents = sshbuf_new()) == NULL) 225519261079SEd Maste fatal_f("sshbuf_new failed"); 225619261079SEd Maste load_server_config(item->filename, 225719261079SEd Maste item->contents); 225819261079SEd Maste parse_server_config_depth(options, 225919261079SEd Maste item->filename, item->contents, 226019261079SEd Maste includes, connectinfo, 226119261079SEd Maste (*inc_flags & SSHCFG_MATCH_ONLY 226219261079SEd Maste ? SSHCFG_MATCH_ONLY : (oactive 226319261079SEd Maste ? 0 : SSHCFG_NEVERMATCH)), 226419261079SEd Maste activep, depth + 1); 226519261079SEd Maste *activep = oactive; 226619261079SEd Maste TAILQ_INSERT_TAIL(includes, item, entry); 226719261079SEd Maste } 226819261079SEd Maste globfree(&gbuf); 226919261079SEd Maste free(arg); 227019261079SEd Maste } 227119261079SEd Maste if (value == 0) { 227219261079SEd Maste fatal("%s line %d: %s missing filename argument", 227319261079SEd Maste filename, linenum, keyword); 227419261079SEd Maste } 227519261079SEd Maste break; 227619261079SEd Maste 2277333ee039SDag-Erling Smørgrav case sMatch: 2278333ee039SDag-Erling Smørgrav if (cmdline) 2279333ee039SDag-Erling Smørgrav fatal("Match directive not supported as a command-line " 2280333ee039SDag-Erling Smørgrav "option"); 228119261079SEd Maste value = match_cfg_line(&str, linenum, 228219261079SEd Maste (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo)); 2283333ee039SDag-Erling Smørgrav if (value < 0) 2284333ee039SDag-Erling Smørgrav fatal("%s line %d: Bad Match condition", filename, 2285333ee039SDag-Erling Smørgrav linenum); 228619261079SEd Maste *activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value; 228719261079SEd Maste /* 228819261079SEd Maste * The MATCH_ONLY flag is applicable only until the first 228919261079SEd Maste * match block. 229019261079SEd Maste */ 229119261079SEd Maste *inc_flags &= ~SSHCFG_MATCH_ONLY; 229219261079SEd Maste /* 229319261079SEd Maste * If match_cfg_line() didn't consume all its arguments then 229419261079SEd Maste * arrange for the extra arguments check below to fail. 229519261079SEd Maste */ 229619261079SEd Maste if (str == NULL || *str == '\0') 229719261079SEd Maste argv_consume(&ac); 2298333ee039SDag-Erling Smørgrav break; 2299333ee039SDag-Erling Smørgrav 2300190cef3dSDag-Erling Smørgrav case sPermitListen: 2301333ee039SDag-Erling Smørgrav case sPermitOpen: 2302190cef3dSDag-Erling Smørgrav if (opcode == sPermitListen) { 2303190cef3dSDag-Erling Smørgrav uintptr = &options->num_permitted_listens; 2304190cef3dSDag-Erling Smørgrav chararrayptr = &options->permitted_listens; 2305190cef3dSDag-Erling Smørgrav } else { 2306190cef3dSDag-Erling Smørgrav uintptr = &options->num_permitted_opens; 2307190cef3dSDag-Erling Smørgrav chararrayptr = &options->permitted_opens; 2308190cef3dSDag-Erling Smørgrav } 2309*a91a2465SEd Maste found = *uintptr == 0; 2310*a91a2465SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 2311*a91a2465SEd Maste if (strcmp(arg, "any") == 0 || 2312*a91a2465SEd Maste strcmp(arg, "none") == 0) { 2313*a91a2465SEd Maste if (nstrs != 0) { 2314*a91a2465SEd Maste fatal("%s line %d: %s must appear " 2315*a91a2465SEd Maste "alone on a %s line.", 2316*a91a2465SEd Maste filename, linenum, arg, keyword); 2317462c32cbSDag-Erling Smørgrav } 2318*a91a2465SEd Maste opt_array_append(filename, linenum, keyword, 2319*a91a2465SEd Maste &strs, &nstrs, arg); 2320*a91a2465SEd Maste continue; 2321462c32cbSDag-Erling Smørgrav } 2322*a91a2465SEd Maste 2323190cef3dSDag-Erling Smørgrav if (opcode == sPermitListen && 2324190cef3dSDag-Erling Smørgrav strchr(arg, ':') == NULL) { 2325190cef3dSDag-Erling Smørgrav /* 2326190cef3dSDag-Erling Smørgrav * Allow bare port number for PermitListen 2327190cef3dSDag-Erling Smørgrav * to indicate a wildcard listen host. 2328190cef3dSDag-Erling Smørgrav */ 2329190cef3dSDag-Erling Smørgrav xasprintf(&arg2, "*:%s", arg); 2330190cef3dSDag-Erling Smørgrav } else { 23314f52dfbbSDag-Erling Smørgrav arg2 = xstrdup(arg); 23321323ec57SEd Maste p = hpdelim(&arg); 23331323ec57SEd Maste if (p == NULL) { 233419261079SEd Maste fatal("%s line %d: %s missing host", 233519261079SEd Maste filename, linenum, keyword); 2336190cef3dSDag-Erling Smørgrav } 2337333ee039SDag-Erling Smørgrav p = cleanhostname(p); 2338190cef3dSDag-Erling Smørgrav } 2339190cef3dSDag-Erling Smørgrav if (arg == NULL || 2340190cef3dSDag-Erling Smørgrav ((port = permitopen_port(arg)) < 0)) { 234119261079SEd Maste fatal("%s line %d: %s bad port number", 234219261079SEd Maste filename, linenum, keyword); 2343190cef3dSDag-Erling Smørgrav } 234419261079SEd Maste opt_array_append(filename, linenum, keyword, 2345*a91a2465SEd Maste &strs, &nstrs, arg2); 23464f52dfbbSDag-Erling Smørgrav free(arg2); 2347333ee039SDag-Erling Smørgrav } 2348*a91a2465SEd Maste if (nstrs == 0) { 2349*a91a2465SEd Maste fatal("%s line %d: %s missing argument.", 2350*a91a2465SEd Maste filename, linenum, keyword); 2351*a91a2465SEd Maste } 2352*a91a2465SEd Maste if (found && *activep) { 2353*a91a2465SEd Maste *chararrayptr = strs; 2354*a91a2465SEd Maste *uintptr = nstrs; 2355*a91a2465SEd Maste strs = NULL; /* transferred */ 2356*a91a2465SEd Maste nstrs = 0; 2357*a91a2465SEd Maste } 2358333ee039SDag-Erling Smørgrav break; 2359333ee039SDag-Erling Smørgrav 2360333ee039SDag-Erling Smørgrav case sForceCommand: 236119261079SEd Maste if (str == NULL || *str == '\0') 236219261079SEd Maste fatal("%s line %d: %s missing argument.", 236319261079SEd Maste filename, linenum, keyword); 236419261079SEd Maste len = strspn(str, WHITESPACE); 2365333ee039SDag-Erling Smørgrav if (*activep && options->adm_forced_command == NULL) 236619261079SEd Maste options->adm_forced_command = xstrdup(str + len); 236719261079SEd Maste argv_consume(&ac); 236819261079SEd Maste break; 2369333ee039SDag-Erling Smørgrav 2370d4af9e69SDag-Erling Smørgrav case sChrootDirectory: 2371d4af9e69SDag-Erling Smørgrav charptr = &options->chroot_directory; 2372d4af9e69SDag-Erling Smørgrav 237319261079SEd Maste arg = argv_next(&ac, &av); 2374d4af9e69SDag-Erling Smørgrav if (!arg || *arg == '\0') 237519261079SEd Maste fatal("%s line %d: %s missing argument.", 237619261079SEd Maste filename, linenum, keyword); 2377d4af9e69SDag-Erling Smørgrav if (*activep && *charptr == NULL) 2378d4af9e69SDag-Erling Smørgrav *charptr = xstrdup(arg); 2379d4af9e69SDag-Erling Smørgrav break; 2380d4af9e69SDag-Erling Smørgrav 2381b15c8340SDag-Erling Smørgrav case sTrustedUserCAKeys: 2382b15c8340SDag-Erling Smørgrav charptr = &options->trusted_user_ca_keys; 2383b15c8340SDag-Erling Smørgrav goto parse_filename; 2384b15c8340SDag-Erling Smørgrav 2385b15c8340SDag-Erling Smørgrav case sRevokedKeys: 2386b15c8340SDag-Erling Smørgrav charptr = &options->revoked_keys_file; 2387b15c8340SDag-Erling Smørgrav goto parse_filename; 2388b15c8340SDag-Erling Smørgrav 238919261079SEd Maste case sSecurityKeyProvider: 239019261079SEd Maste charptr = &options->sk_provider; 239119261079SEd Maste arg = argv_next(&ac, &av); 239219261079SEd Maste if (!arg || *arg == '\0') 239319261079SEd Maste fatal("%s line %d: %s missing argument.", 239419261079SEd Maste filename, linenum, keyword); 239519261079SEd Maste if (*activep && *charptr == NULL) { 239619261079SEd Maste *charptr = strcasecmp(arg, "internal") == 0 ? 239719261079SEd Maste xstrdup(arg) : derelativise_path(arg); 239819261079SEd Maste /* increase optional counter */ 239919261079SEd Maste if (intptr != NULL) 240019261079SEd Maste *intptr = *intptr + 1; 240119261079SEd Maste } 240219261079SEd Maste break; 240319261079SEd Maste 24044a421b63SDag-Erling Smørgrav case sIPQoS: 240519261079SEd Maste arg = argv_next(&ac, &av); 240619261079SEd Maste if (!arg || *arg == '\0') 240719261079SEd Maste fatal("%s line %d: %s missing argument.", 240819261079SEd Maste filename, linenum, keyword); 24094a421b63SDag-Erling Smørgrav if ((value = parse_ipqos(arg)) == -1) 241019261079SEd Maste fatal("%s line %d: Bad %s value: %s", 241119261079SEd Maste filename, linenum, keyword, arg); 241219261079SEd Maste arg = argv_next(&ac, &av); 24134a421b63SDag-Erling Smørgrav if (arg == NULL) 24144a421b63SDag-Erling Smørgrav value2 = value; 24154a421b63SDag-Erling Smørgrav else if ((value2 = parse_ipqos(arg)) == -1) 241619261079SEd Maste fatal("%s line %d: Bad %s value: %s", 241719261079SEd Maste filename, linenum, keyword, arg); 24184a421b63SDag-Erling Smørgrav if (*activep) { 24194a421b63SDag-Erling Smørgrav options->ip_qos_interactive = value; 24204a421b63SDag-Erling Smørgrav options->ip_qos_bulk = value2; 24214a421b63SDag-Erling Smørgrav } 24224a421b63SDag-Erling Smørgrav break; 24234a421b63SDag-Erling Smørgrav 2424db58a8e4SDag-Erling Smørgrav case sVersionAddendum: 242519261079SEd Maste if (str == NULL || *str == '\0') 242619261079SEd Maste fatal("%s line %d: %s missing argument.", 242719261079SEd Maste filename, linenum, keyword); 242819261079SEd Maste len = strspn(str, WHITESPACE); 242919261079SEd Maste if (strchr(str + len, '\r') != NULL) { 243019261079SEd Maste fatal("%.200s line %d: Invalid %s argument", 243119261079SEd Maste filename, linenum, keyword); 2432462c32cbSDag-Erling Smørgrav } 243319261079SEd Maste if ((arg = strchr(line, '#')) != NULL) { 243419261079SEd Maste *arg = '\0'; 243519261079SEd Maste rtrim(line); 243619261079SEd Maste } 243719261079SEd Maste if (*activep && options->version_addendum == NULL) { 243819261079SEd Maste if (strcasecmp(str + len, "none") == 0) 243919261079SEd Maste options->version_addendum = xstrdup(""); 244019261079SEd Maste else 244119261079SEd Maste options->version_addendum = xstrdup(str + len); 244219261079SEd Maste } 244319261079SEd Maste argv_consume(&ac); 244419261079SEd Maste break; 2445db58a8e4SDag-Erling Smørgrav 24466888a9beSDag-Erling Smørgrav case sAuthorizedKeysCommand: 244719261079SEd Maste charptr = &options->authorized_keys_command; 244819261079SEd Maste parse_command: 244919261079SEd Maste len = strspn(str, WHITESPACE); 245019261079SEd Maste if (str[len] != '/' && strcasecmp(str + len, "none") != 0) { 245119261079SEd Maste fatal("%.200s line %d: %s must be an absolute path", 245219261079SEd Maste filename, linenum, keyword); 24536888a9beSDag-Erling Smørgrav } 2454535af610SEd Maste if (*activep && *charptr == NULL) 245519261079SEd Maste *charptr = xstrdup(str + len); 245619261079SEd Maste argv_consume(&ac); 245719261079SEd Maste break; 24586888a9beSDag-Erling Smørgrav 24596888a9beSDag-Erling Smørgrav case sAuthorizedKeysCommandUser: 24606888a9beSDag-Erling Smørgrav charptr = &options->authorized_keys_command_user; 246119261079SEd Maste parse_localuser: 246219261079SEd Maste arg = argv_next(&ac, &av); 246319261079SEd Maste if (!arg || *arg == '\0') { 246419261079SEd Maste fatal("%s line %d: missing %s argument.", 246519261079SEd Maste filename, linenum, keyword); 246619261079SEd Maste } 24676888a9beSDag-Erling Smørgrav if (*activep && *charptr == NULL) 24686888a9beSDag-Erling Smørgrav *charptr = xstrdup(arg); 24696888a9beSDag-Erling Smørgrav break; 24706888a9beSDag-Erling Smørgrav 2471557f75e5SDag-Erling Smørgrav case sAuthorizedPrincipalsCommand: 247219261079SEd Maste charptr = &options->authorized_principals_command; 247319261079SEd Maste goto parse_command; 2474557f75e5SDag-Erling Smørgrav 2475557f75e5SDag-Erling Smørgrav case sAuthorizedPrincipalsCommandUser: 2476557f75e5SDag-Erling Smørgrav charptr = &options->authorized_principals_command_user; 247719261079SEd Maste goto parse_localuser; 2478557f75e5SDag-Erling Smørgrav 24796888a9beSDag-Erling Smørgrav case sAuthenticationMethods: 248019261079SEd Maste found = options->num_auth_methods == 0; 2481076ad2f8SDag-Erling Smørgrav value = 0; /* seen "any" pseudo-method */ 248219261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 2483076ad2f8SDag-Erling Smørgrav if (strcmp(arg, "any") == 0) { 2484*a91a2465SEd Maste if (nstrs > 0) { 248519261079SEd Maste fatal("%s line %d: \"any\" must " 248619261079SEd Maste "appear alone in %s", 248719261079SEd Maste filename, linenum, keyword); 2488076ad2f8SDag-Erling Smørgrav } 2489076ad2f8SDag-Erling Smørgrav value = 1; 2490076ad2f8SDag-Erling Smørgrav } else if (value) { 2491076ad2f8SDag-Erling Smørgrav fatal("%s line %d: \"any\" must appear " 249219261079SEd Maste "alone in %s", filename, linenum, keyword); 2493076ad2f8SDag-Erling Smørgrav } else if (auth2_methods_valid(arg, 0) != 0) { 249419261079SEd Maste fatal("%s line %d: invalid %s method list.", 249519261079SEd Maste filename, linenum, keyword); 2496076ad2f8SDag-Erling Smørgrav } 249719261079SEd Maste opt_array_append(filename, linenum, keyword, 2498*a91a2465SEd Maste &strs, &nstrs, arg); 24996888a9beSDag-Erling Smørgrav } 2500*a91a2465SEd Maste if (nstrs == 0) { 250119261079SEd Maste fatal("%s line %d: no %s specified", 250219261079SEd Maste filename, linenum, keyword); 2503076ad2f8SDag-Erling Smørgrav } 2504*a91a2465SEd Maste if (found && *activep) { 2505*a91a2465SEd Maste options->auth_methods = strs; 2506*a91a2465SEd Maste options->num_auth_methods = nstrs; 2507*a91a2465SEd Maste strs = NULL; /* transferred */ 2508*a91a2465SEd Maste nstrs = 0; 2509*a91a2465SEd Maste } 251019261079SEd Maste break; 25116888a9beSDag-Erling Smørgrav 2512a0ee8cc6SDag-Erling Smørgrav case sStreamLocalBindMask: 251319261079SEd Maste arg = argv_next(&ac, &av); 2514a0ee8cc6SDag-Erling Smørgrav if (!arg || *arg == '\0') 251519261079SEd Maste fatal("%s line %d: %s missing argument.", 251619261079SEd Maste filename, linenum, keyword); 2517a0ee8cc6SDag-Erling Smørgrav /* Parse mode in octal format */ 2518a0ee8cc6SDag-Erling Smørgrav value = strtol(arg, &p, 8); 2519a0ee8cc6SDag-Erling Smørgrav if (arg == p || value < 0 || value > 0777) 252019261079SEd Maste fatal("%s line %d: Invalid %s.", 252119261079SEd Maste filename, linenum, keyword); 2522557f75e5SDag-Erling Smørgrav if (*activep) 2523a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)value; 2524a0ee8cc6SDag-Erling Smørgrav break; 2525a0ee8cc6SDag-Erling Smørgrav 2526a0ee8cc6SDag-Erling Smørgrav case sStreamLocalBindUnlink: 2527a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.streamlocal_bind_unlink; 2528a0ee8cc6SDag-Erling Smørgrav goto parse_flag; 2529a0ee8cc6SDag-Erling Smørgrav 2530bc5531deSDag-Erling Smørgrav case sFingerprintHash: 253119261079SEd Maste arg = argv_next(&ac, &av); 2532bc5531deSDag-Erling Smørgrav if (!arg || *arg == '\0') 253319261079SEd Maste fatal("%s line %d: %s missing argument.", 253419261079SEd Maste filename, linenum, keyword); 2535bc5531deSDag-Erling Smørgrav if ((value = ssh_digest_alg_by_name(arg)) == -1) 253619261079SEd Maste fatal("%.200s line %d: Invalid %s algorithm \"%s\".", 253719261079SEd Maste filename, linenum, keyword, arg); 2538bc5531deSDag-Erling Smørgrav if (*activep) 2539bc5531deSDag-Erling Smørgrav options->fingerprint_hash = value; 2540bc5531deSDag-Erling Smørgrav break; 2541bc5531deSDag-Erling Smørgrav 25424f52dfbbSDag-Erling Smørgrav case sExposeAuthInfo: 25434f52dfbbSDag-Erling Smørgrav intptr = &options->expose_userauth_info; 25444f52dfbbSDag-Erling Smørgrav goto parse_flag; 25454f52dfbbSDag-Erling Smørgrav 254647dd1d1bSDag-Erling Smørgrav case sRDomain: 254719261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN) 254819261079SEd Maste fatal("%s line %d: setting RDomain not supported on this " 254919261079SEd Maste "platform.", filename, linenum); 255019261079SEd Maste #endif 255147dd1d1bSDag-Erling Smørgrav charptr = &options->routing_domain; 255219261079SEd Maste arg = argv_next(&ac, &av); 255347dd1d1bSDag-Erling Smørgrav if (!arg || *arg == '\0') 255419261079SEd Maste fatal("%s line %d: %s missing argument.", 255519261079SEd Maste filename, linenum, keyword); 255647dd1d1bSDag-Erling Smørgrav if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 && 255747dd1d1bSDag-Erling Smørgrav !valid_rdomain(arg)) 255819261079SEd Maste fatal("%s line %d: invalid routing domain", 255947dd1d1bSDag-Erling Smørgrav filename, linenum); 256047dd1d1bSDag-Erling Smørgrav if (*activep && *charptr == NULL) 256147dd1d1bSDag-Erling Smørgrav *charptr = xstrdup(arg); 256247dd1d1bSDag-Erling Smørgrav break; 256347dd1d1bSDag-Erling Smørgrav 256438a52bd3SEd Maste case sRequiredRSASize: 256538a52bd3SEd Maste intptr = &options->required_rsa_size; 256638a52bd3SEd Maste goto parse_int; 256738a52bd3SEd Maste 2568f374ba41SEd Maste case sChannelTimeout: 2569*a91a2465SEd Maste found = options->num_channel_timeouts == 0; 2570f374ba41SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 2571f374ba41SEd Maste /* Allow "none" only in first position */ 2572f374ba41SEd Maste if (strcasecmp(arg, "none") == 0) { 2573*a91a2465SEd Maste if (nstrs > 0 || ac > 0) { 2574f374ba41SEd Maste error("%s line %d: keyword %s \"none\" " 2575f374ba41SEd Maste "argument must appear alone.", 2576f374ba41SEd Maste filename, linenum, keyword); 2577f374ba41SEd Maste goto out; 2578f374ba41SEd Maste } 2579069ac184SEd Maste } else if (parse_pattern_interval(arg, 2580069ac184SEd Maste NULL, NULL) != 0) { 2581f374ba41SEd Maste fatal("%s line %d: invalid channel timeout %s", 2582f374ba41SEd Maste filename, linenum, arg); 2583f374ba41SEd Maste } 2584f374ba41SEd Maste opt_array_append(filename, linenum, keyword, 2585*a91a2465SEd Maste &strs, &nstrs, arg); 2586*a91a2465SEd Maste } 2587*a91a2465SEd Maste if (nstrs == 0) { 2588*a91a2465SEd Maste fatal("%s line %d: no %s specified", 2589*a91a2465SEd Maste filename, linenum, keyword); 2590*a91a2465SEd Maste } 2591*a91a2465SEd Maste if (found && *activep) { 2592*a91a2465SEd Maste options->channel_timeouts = strs; 2593*a91a2465SEd Maste options->num_channel_timeouts = nstrs; 2594*a91a2465SEd Maste strs = NULL; /* transferred */ 2595*a91a2465SEd Maste nstrs = 0; 2596f374ba41SEd Maste } 2597f374ba41SEd Maste break; 2598f374ba41SEd Maste 2599f374ba41SEd Maste case sUnusedConnectionTimeout: 2600f374ba41SEd Maste intptr = &options->unused_connection_timeout; 2601f374ba41SEd Maste /* peek at first arg for "none" so we can reuse parse_time */ 2602f374ba41SEd Maste if (av[0] != NULL && strcasecmp(av[0], "none") == 0) { 2603f374ba41SEd Maste (void)argv_next(&ac, &av); /* consume arg */ 2604f374ba41SEd Maste if (*activep) 2605f374ba41SEd Maste *intptr = 0; 2606f374ba41SEd Maste break; 2607f374ba41SEd Maste } 2608f374ba41SEd Maste goto parse_time; 2609f374ba41SEd Maste 2610b2af61ecSKurt Lidl case sUseBlacklist: 2611b2af61ecSKurt Lidl intptr = &options->use_blacklist; 2612b2af61ecSKurt Lidl goto parse_flag; 2613b2af61ecSKurt Lidl 2614af12a3e7SDag-Erling Smørgrav case sDeprecated: 2615ca86bcf2SDag-Erling Smørgrav case sIgnore: 2616cf2b5f3bSDag-Erling Smørgrav case sUnsupported: 2617ca86bcf2SDag-Erling Smørgrav do_log2(opcode == sIgnore ? 2618ca86bcf2SDag-Erling Smørgrav SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO, 2619ca86bcf2SDag-Erling Smørgrav "%s line %d: %s option %s", filename, linenum, 262019261079SEd Maste opcode == sUnsupported ? "Unsupported" : "Deprecated", 262119261079SEd Maste keyword); 262219261079SEd Maste argv_consume(&ac); 2623af12a3e7SDag-Erling Smørgrav break; 2624af12a3e7SDag-Erling Smørgrav 262542f71286SMark Murray default: 2626af12a3e7SDag-Erling Smørgrav fatal("%s line %d: Missing handler for opcode %s (%d)", 262719261079SEd Maste filename, linenum, keyword, opcode); 2628511b41d2SMark Murray } 262919261079SEd Maste /* Check that there is no garbage at end of line. */ 263019261079SEd Maste if (ac > 0) { 263119261079SEd Maste error("%.200s line %d: keyword %s extra arguments " 263219261079SEd Maste "at end of line", filename, linenum, keyword); 263319261079SEd Maste goto out; 2634af12a3e7SDag-Erling Smørgrav } 2635af12a3e7SDag-Erling Smørgrav 263619261079SEd Maste /* success */ 263719261079SEd Maste ret = 0; 263819261079SEd Maste out: 2639*a91a2465SEd Maste opt_array_free2(strs, NULL, nstrs); 264019261079SEd Maste argv_free(oav, oac); 264119261079SEd Maste return ret; 264219261079SEd Maste } 264319261079SEd Maste 264419261079SEd Maste int 264519261079SEd Maste process_server_config_line(ServerOptions *options, char *line, 264619261079SEd Maste const char *filename, int linenum, int *activep, 264719261079SEd Maste struct connection_info *connectinfo, struct include_list *includes) 264819261079SEd Maste { 264919261079SEd Maste int inc_flags = 0; 265019261079SEd Maste 265119261079SEd Maste return process_server_config_line_depth(options, line, filename, 265219261079SEd Maste linenum, activep, connectinfo, &inc_flags, 0, includes); 265319261079SEd Maste } 265419261079SEd Maste 265519261079SEd Maste 2656af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */ 2657af12a3e7SDag-Erling Smørgrav 2658af12a3e7SDag-Erling Smørgrav void 2659190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf) 2660af12a3e7SDag-Erling Smørgrav { 266119261079SEd Maste struct stat st; 2662190cef3dSDag-Erling Smørgrav char *line = NULL, *cp; 2663190cef3dSDag-Erling Smørgrav size_t linesize = 0; 2664a82e551fSDag-Erling Smørgrav FILE *f; 2665f374ba41SEd Maste int r; 2666af12a3e7SDag-Erling Smørgrav 266719261079SEd Maste debug2_f("filename %s", filename); 266821e764dfSDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) { 2669af12a3e7SDag-Erling Smørgrav perror(filename); 2670af12a3e7SDag-Erling Smørgrav exit(1); 2671af12a3e7SDag-Erling Smørgrav } 2672190cef3dSDag-Erling Smørgrav sshbuf_reset(conf); 267319261079SEd Maste /* grow buffer, so realloc is avoided for large config files */ 267419261079SEd Maste if (fstat(fileno(f), &st) == 0 && st.st_size > 0 && 267519261079SEd Maste (r = sshbuf_allocate(conf, st.st_size)) != 0) 267619261079SEd Maste fatal_fr(r, "allocate"); 2677190cef3dSDag-Erling Smørgrav while (getline(&line, &linesize, f) != -1) { 267821e764dfSDag-Erling Smørgrav /* 267919261079SEd Maste * Strip whitespace 268021e764dfSDag-Erling Smørgrav * NB - preserve newlines, they are needed to reproduce 268121e764dfSDag-Erling Smørgrav * line numbers later for error messages 268221e764dfSDag-Erling Smørgrav */ 268321e764dfSDag-Erling Smørgrav cp = line + strspn(line, " \t\r"); 2684190cef3dSDag-Erling Smørgrav if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0) 268519261079SEd Maste fatal_fr(r, "sshbuf_put"); 268621e764dfSDag-Erling Smørgrav } 2687190cef3dSDag-Erling Smørgrav free(line); 2688190cef3dSDag-Erling Smørgrav if ((r = sshbuf_put_u8(conf, 0)) != 0) 268919261079SEd Maste fatal_fr(r, "sshbuf_put_u8"); 269021e764dfSDag-Erling Smørgrav fclose(f); 269119261079SEd Maste debug2_f("done config len = %zu", sshbuf_len(conf)); 269221e764dfSDag-Erling Smørgrav } 269321e764dfSDag-Erling Smørgrav 269421e764dfSDag-Erling Smørgrav void 2695462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options, 269619261079SEd Maste struct include_list *includes, struct connection_info *connectinfo) 269721e764dfSDag-Erling Smørgrav { 2698333ee039SDag-Erling Smørgrav ServerOptions mo; 2699333ee039SDag-Erling Smørgrav 2700333ee039SDag-Erling Smørgrav initialize_server_options(&mo); 270119261079SEd Maste parse_server_config(&mo, "reprocess config", cfg, includes, 270287c1498dSEd Maste connectinfo, 0); 2703d4af9e69SDag-Erling Smørgrav copy_set_server_options(options, &mo, 0); 2704333ee039SDag-Erling Smørgrav } 2705333ee039SDag-Erling Smørgrav 2706462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec) 2707462c32cbSDag-Erling Smørgrav { 2708462c32cbSDag-Erling Smørgrav char *p; 2709462c32cbSDag-Erling Smørgrav 2710462c32cbSDag-Erling Smørgrav while ((p = strsep(&spec, ",")) && *p != '\0') { 2711462c32cbSDag-Erling Smørgrav if (strncmp(p, "addr=", 5) == 0) { 2712462c32cbSDag-Erling Smørgrav ci->address = xstrdup(p + 5); 2713462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "host=", 5) == 0) { 2714462c32cbSDag-Erling Smørgrav ci->host = xstrdup(p + 5); 2715462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "user=", 5) == 0) { 2716462c32cbSDag-Erling Smørgrav ci->user = xstrdup(p + 5); 2717462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "laddr=", 6) == 0) { 2718462c32cbSDag-Erling Smørgrav ci->laddress = xstrdup(p + 6); 271947dd1d1bSDag-Erling Smørgrav } else if (strncmp(p, "rdomain=", 8) == 0) { 272047dd1d1bSDag-Erling Smørgrav ci->rdomain = xstrdup(p + 8); 2721462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "lport=", 6) == 0) { 2722462c32cbSDag-Erling Smørgrav ci->lport = a2port(p + 6); 2723462c32cbSDag-Erling Smørgrav if (ci->lport == -1) { 2724462c32cbSDag-Erling Smørgrav fprintf(stderr, "Invalid port '%s' in test mode" 2725462c32cbSDag-Erling Smørgrav " specification %s\n", p+6, p); 2726462c32cbSDag-Erling Smørgrav return -1; 2727462c32cbSDag-Erling Smørgrav } 2728462c32cbSDag-Erling Smørgrav } else { 2729462c32cbSDag-Erling Smørgrav fprintf(stderr, "Invalid test mode specification %s\n", 2730462c32cbSDag-Erling Smørgrav p); 2731462c32cbSDag-Erling Smørgrav return -1; 2732462c32cbSDag-Erling Smørgrav } 2733462c32cbSDag-Erling Smørgrav } 2734462c32cbSDag-Erling Smørgrav return 0; 2735462c32cbSDag-Erling Smørgrav } 2736462c32cbSDag-Erling Smørgrav 2737edf85781SEd Maste void 2738edf85781SEd Maste servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src) 2739edf85781SEd Maste { 2740edf85781SEd Maste u_int i, j, found; 2741edf85781SEd Maste 2742edf85781SEd Maste for (i = 0; i < src->num_subsystems; i++) { 2743edf85781SEd Maste found = 0; 2744edf85781SEd Maste for (j = 0; j < dst->num_subsystems; j++) { 2745edf85781SEd Maste if (strcmp(src->subsystem_name[i], 2746edf85781SEd Maste dst->subsystem_name[j]) == 0) { 2747edf85781SEd Maste found = 1; 2748edf85781SEd Maste break; 2749edf85781SEd Maste } 2750edf85781SEd Maste } 2751edf85781SEd Maste if (found) { 2752edf85781SEd Maste debug_f("override \"%s\"", dst->subsystem_name[j]); 2753edf85781SEd Maste free(dst->subsystem_command[j]); 2754edf85781SEd Maste free(dst->subsystem_args[j]); 2755edf85781SEd Maste dst->subsystem_command[j] = 2756edf85781SEd Maste xstrdup(src->subsystem_command[i]); 2757edf85781SEd Maste dst->subsystem_args[j] = 2758edf85781SEd Maste xstrdup(src->subsystem_args[i]); 2759edf85781SEd Maste continue; 2760edf85781SEd Maste } 2761edf85781SEd Maste debug_f("add \"%s\"", src->subsystem_name[i]); 2762edf85781SEd Maste dst->subsystem_name = xrecallocarray( 2763edf85781SEd Maste dst->subsystem_name, dst->num_subsystems, 2764edf85781SEd Maste dst->num_subsystems + 1, sizeof(*dst->subsystem_name)); 2765edf85781SEd Maste dst->subsystem_command = xrecallocarray( 2766edf85781SEd Maste dst->subsystem_command, dst->num_subsystems, 2767edf85781SEd Maste dst->num_subsystems + 1, sizeof(*dst->subsystem_command)); 2768edf85781SEd Maste dst->subsystem_args = xrecallocarray( 2769edf85781SEd Maste dst->subsystem_args, dst->num_subsystems, 2770edf85781SEd Maste dst->num_subsystems + 1, sizeof(*dst->subsystem_args)); 2771edf85781SEd Maste j = dst->num_subsystems++; 2772edf85781SEd Maste dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]); 2773edf85781SEd Maste dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]); 2774edf85781SEd Maste dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]); 2775edf85781SEd Maste } 2776edf85781SEd Maste } 2777edf85781SEd Maste 2778462c32cbSDag-Erling Smørgrav /* 2779d4af9e69SDag-Erling Smørgrav * Copy any supported values that are set. 2780d4af9e69SDag-Erling Smørgrav * 27817aee6ffeSDag-Erling Smørgrav * If the preauth flag is set, we do not bother copying the string or 2782d4af9e69SDag-Erling Smørgrav * array values that are not used pre-authentication, because any that we 2783190cef3dSDag-Erling Smørgrav * do use must be explicitly sent in mm_getpwnamallow(). 2784d4af9e69SDag-Erling Smørgrav */ 2785333ee039SDag-Erling Smørgrav void 2786d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) 2787333ee039SDag-Erling Smørgrav { 2788f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\ 2789f7167e0eSDag-Erling Smørgrav if (src->n != -1) \ 2790f7167e0eSDag-Erling Smørgrav dst->n = src->n; \ 2791f7167e0eSDag-Erling Smørgrav } while (0) 2792f7167e0eSDag-Erling Smørgrav 2793d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(password_authentication); 2794d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(gss_authentication); 2795d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(pubkey_authentication); 279619261079SEd Maste M_CP_INTOPT(pubkey_auth_options); 2797d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(kerberos_authentication); 2798d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(hostbased_authentication); 2799e2f6069cSDag-Erling Smørgrav M_CP_INTOPT(hostbased_uses_name_from_packet_only); 2800d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(kbd_interactive_authentication); 2801d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(permit_root_login); 2802cce7d346SDag-Erling Smørgrav M_CP_INTOPT(permit_empty_passwd); 280319261079SEd Maste M_CP_INTOPT(ignore_rhosts); 2804d4af9e69SDag-Erling Smørgrav 2805d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(allow_tcp_forwarding); 2806a0ee8cc6SDag-Erling Smørgrav M_CP_INTOPT(allow_streamlocal_forwarding); 2807d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(allow_agent_forwarding); 2808ca86bcf2SDag-Erling Smørgrav M_CP_INTOPT(disable_forwarding); 28094f52dfbbSDag-Erling Smørgrav M_CP_INTOPT(expose_userauth_info); 2810e2f6069cSDag-Erling Smørgrav M_CP_INTOPT(permit_tun); 2811a0ee8cc6SDag-Erling Smørgrav M_CP_INTOPT(fwd_opts.gateway_ports); 2812076ad2f8SDag-Erling Smørgrav M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); 2813d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(x11_display_offset); 2814d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(x11_forwarding); 2815d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(x11_use_localhost); 2816f7167e0eSDag-Erling Smørgrav M_CP_INTOPT(permit_tty); 2817a0ee8cc6SDag-Erling Smørgrav M_CP_INTOPT(permit_user_rc); 2818d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(max_sessions); 2819d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(max_authtries); 2820ca86bcf2SDag-Erling Smørgrav M_CP_INTOPT(client_alive_count_max); 2821ca86bcf2SDag-Erling Smørgrav M_CP_INTOPT(client_alive_interval); 28224a421b63SDag-Erling Smørgrav M_CP_INTOPT(ip_qos_interactive); 28234a421b63SDag-Erling Smørgrav M_CP_INTOPT(ip_qos_bulk); 2824e4a9863fSDag-Erling Smørgrav M_CP_INTOPT(rekey_limit); 2825e4a9863fSDag-Erling Smørgrav M_CP_INTOPT(rekey_interval); 28264f52dfbbSDag-Erling Smørgrav M_CP_INTOPT(log_level); 282738a52bd3SEd Maste M_CP_INTOPT(required_rsa_size); 2828f374ba41SEd Maste M_CP_INTOPT(unused_connection_timeout); 2829d4af9e69SDag-Erling Smørgrav 2830076ad2f8SDag-Erling Smørgrav /* 2831076ad2f8SDag-Erling Smørgrav * The bind_mask is a mode_t that may be unsigned, so we can't use 2832076ad2f8SDag-Erling Smørgrav * M_CP_INTOPT - it does a signed comparison that causes compiler 2833076ad2f8SDag-Erling Smørgrav * warnings. 2834076ad2f8SDag-Erling Smørgrav */ 2835076ad2f8SDag-Erling Smørgrav if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) { 2836076ad2f8SDag-Erling Smørgrav dst->fwd_opts.streamlocal_bind_mask = 2837076ad2f8SDag-Erling Smørgrav src->fwd_opts.streamlocal_bind_mask; 2838076ad2f8SDag-Erling Smørgrav } 2839076ad2f8SDag-Erling Smørgrav 2840f7167e0eSDag-Erling Smørgrav /* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */ 2841f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\ 2842f7167e0eSDag-Erling Smørgrav if (src->n != NULL && dst->n != src->n) { \ 2843f7167e0eSDag-Erling Smørgrav free(dst->n); \ 2844f7167e0eSDag-Erling Smørgrav dst->n = src->n; \ 2845f7167e0eSDag-Erling Smørgrav } \ 2846f7167e0eSDag-Erling Smørgrav } while(0) 284747dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\ 284847dd1d1bSDag-Erling Smørgrav u_int i; \ 284947dd1d1bSDag-Erling Smørgrav if (src->num_s != 0) { \ 285047dd1d1bSDag-Erling Smørgrav for (i = 0; i < dst->num_s; i++) \ 285147dd1d1bSDag-Erling Smørgrav free(dst->s[i]); \ 285247dd1d1bSDag-Erling Smørgrav free(dst->s); \ 285347dd1d1bSDag-Erling Smørgrav dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \ 285447dd1d1bSDag-Erling Smørgrav for (i = 0; i < src->num_s; i++) \ 285547dd1d1bSDag-Erling Smørgrav dst->s[i] = xstrdup(src->s[i]); \ 285647dd1d1bSDag-Erling Smørgrav dst->num_s = src->num_s; \ 28574f52dfbbSDag-Erling Smørgrav } \ 28584f52dfbbSDag-Erling Smørgrav } while(0) 2859f7167e0eSDag-Erling Smørgrav 2860e146993eSDag-Erling Smørgrav /* See comment in servconf.h */ 2861e146993eSDag-Erling Smørgrav COPY_MATCH_STRING_OPTS(); 2862e146993eSDag-Erling Smørgrav 2863acc1a9efSDag-Erling Smørgrav /* Arguments that accept '+...' need to be expanded */ 2864acc1a9efSDag-Erling Smørgrav assemble_algorithms(dst); 2865acc1a9efSDag-Erling Smørgrav 2866e146993eSDag-Erling Smørgrav /* 2867e146993eSDag-Erling Smørgrav * The only things that should be below this point are string options 2868e146993eSDag-Erling Smørgrav * which are only used after authentication. 2869e146993eSDag-Erling Smørgrav */ 2870d4af9e69SDag-Erling Smørgrav if (preauth) 2871d4af9e69SDag-Erling Smørgrav return; 2872e146993eSDag-Erling Smørgrav 2873acc1a9efSDag-Erling Smørgrav /* These options may be "none" to clear a global setting */ 2874d4af9e69SDag-Erling Smørgrav M_CP_STROPT(adm_forced_command); 2875acc1a9efSDag-Erling Smørgrav if (option_clear_or_none(dst->adm_forced_command)) { 2876acc1a9efSDag-Erling Smørgrav free(dst->adm_forced_command); 2877acc1a9efSDag-Erling Smørgrav dst->adm_forced_command = NULL; 2878acc1a9efSDag-Erling Smørgrav } 2879d4af9e69SDag-Erling Smørgrav M_CP_STROPT(chroot_directory); 2880acc1a9efSDag-Erling Smørgrav if (option_clear_or_none(dst->chroot_directory)) { 2881acc1a9efSDag-Erling Smørgrav free(dst->chroot_directory); 2882acc1a9efSDag-Erling Smørgrav dst->chroot_directory = NULL; 2883acc1a9efSDag-Erling Smørgrav } 2884edf85781SEd Maste 2885edf85781SEd Maste /* Subsystems require merging. */ 2886edf85781SEd Maste servconf_merge_subsystems(dst, src); 2887333ee039SDag-Erling Smørgrav } 2888d4af9e69SDag-Erling Smørgrav 2889d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT 2890d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT 2891e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT 2892333ee039SDag-Erling Smørgrav 289319261079SEd Maste #define SERVCONF_MAX_DEPTH 16 289419261079SEd Maste static void 289519261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename, 289619261079SEd Maste struct sshbuf *conf, struct include_list *includes, 289719261079SEd Maste struct connection_info *connectinfo, int flags, int *activep, int depth) 2898333ee039SDag-Erling Smørgrav { 289919261079SEd Maste int linenum, bad_options = 0; 290021e764dfSDag-Erling Smørgrav char *cp, *obuf, *cbuf; 290121e764dfSDag-Erling Smørgrav 290219261079SEd Maste if (depth < 0 || depth > SERVCONF_MAX_DEPTH) 290319261079SEd Maste fatal("Too many recursive configuration includes"); 290419261079SEd Maste 290519261079SEd Maste debug2_f("config %s len %zu%s", filename, sshbuf_len(conf), 290619261079SEd Maste (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : "")); 290721e764dfSDag-Erling Smørgrav 2908076ad2f8SDag-Erling Smørgrav if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) 290919261079SEd Maste fatal_f("sshbuf_dup_string failed"); 291021e764dfSDag-Erling Smørgrav linenum = 1; 291121e764dfSDag-Erling Smørgrav while ((cp = strsep(&cbuf, "\n")) != NULL) { 291219261079SEd Maste if (process_server_config_line_depth(options, cp, 291319261079SEd Maste filename, linenum++, activep, connectinfo, &flags, 291419261079SEd Maste depth, includes) != 0) 2915af12a3e7SDag-Erling Smørgrav bad_options++; 2916511b41d2SMark Murray } 2917e4a9863fSDag-Erling Smørgrav free(obuf); 2918ca3176e7SBrian Feldman if (bad_options > 0) 2919af12a3e7SDag-Erling Smørgrav fatal("%s: terminating, %d bad configuration options", 2920511b41d2SMark Murray filename, bad_options); 292119261079SEd Maste } 292219261079SEd Maste 292319261079SEd Maste void 292419261079SEd Maste parse_server_config(ServerOptions *options, const char *filename, 292519261079SEd Maste struct sshbuf *conf, struct include_list *includes, 292687c1498dSEd Maste struct connection_info *connectinfo, int reexec) 292719261079SEd Maste { 292819261079SEd Maste int active = connectinfo ? 0 : 1; 292919261079SEd Maste parse_server_config_depth(options, filename, conf, includes, 293019261079SEd Maste connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0); 293187c1498dSEd Maste if (!reexec) 2932557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(options); 2933511b41d2SMark Murray } 2934d4af9e69SDag-Erling Smørgrav 2935d4af9e69SDag-Erling Smørgrav static const char * 2936e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m) 2937d4af9e69SDag-Erling Smørgrav { 2938e146993eSDag-Erling Smørgrav u_int i; 2939e146993eSDag-Erling Smørgrav 2940e146993eSDag-Erling Smørgrav for (i = 0; m[i].key != NULL; i++) { 2941e146993eSDag-Erling Smørgrav if (m[i].value == val) 2942e146993eSDag-Erling Smørgrav return m[i].key; 2943e146993eSDag-Erling Smørgrav } 2944d4af9e69SDag-Erling Smørgrav return "UNKNOWN"; 2945d4af9e69SDag-Erling Smørgrav } 2946e146993eSDag-Erling Smørgrav 2947e146993eSDag-Erling Smørgrav static const char * 2948e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val) 2949e146993eSDag-Erling Smørgrav { 2950e146993eSDag-Erling Smørgrav if (val == -1) 2951e146993eSDag-Erling Smørgrav return "unset"; 2952e146993eSDag-Erling Smørgrav switch (code) { 2953e146993eSDag-Erling Smørgrav case sAddressFamily: 2954e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_addressfamily); 2955e146993eSDag-Erling Smørgrav case sPermitRootLogin: 2956e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_permitrootlogin); 2957e146993eSDag-Erling Smørgrav case sGatewayPorts: 2958e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_gatewayports); 2959e146993eSDag-Erling Smørgrav case sCompression: 2960e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_compression); 29616888a9beSDag-Erling Smørgrav case sAllowTcpForwarding: 29626888a9beSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tcpfwd); 2963a0ee8cc6SDag-Erling Smørgrav case sAllowStreamLocalForwarding: 2964a0ee8cc6SDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tcpfwd); 296519261079SEd Maste case sIgnoreRhosts: 296619261079SEd Maste return fmt_multistate_int(val, multistate_ignore_rhosts); 2967bc5531deSDag-Erling Smørgrav case sFingerprintHash: 2968bc5531deSDag-Erling Smørgrav return ssh_digest_alg_name(val); 2969e146993eSDag-Erling Smørgrav default: 2970d4af9e69SDag-Erling Smørgrav switch (val) { 2971d4af9e69SDag-Erling Smørgrav case 0: 2972d4af9e69SDag-Erling Smørgrav return "no"; 2973d4af9e69SDag-Erling Smørgrav case 1: 2974d4af9e69SDag-Erling Smørgrav return "yes"; 2975e146993eSDag-Erling Smørgrav default: 2976d4af9e69SDag-Erling Smørgrav return "UNKNOWN"; 2977d4af9e69SDag-Erling Smørgrav } 2978e146993eSDag-Erling Smørgrav } 2979e146993eSDag-Erling Smørgrav } 2980d4af9e69SDag-Erling Smørgrav 2981d4af9e69SDag-Erling Smørgrav static void 2982d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val) 2983d4af9e69SDag-Erling Smørgrav { 2984f374ba41SEd Maste if (code == sUnusedConnectionTimeout && val == 0) { 2985f374ba41SEd Maste printf("%s none\n", lookup_opcode_name(code)); 2986f374ba41SEd Maste return; 2987f374ba41SEd Maste } 2988d4af9e69SDag-Erling Smørgrav printf("%s %d\n", lookup_opcode_name(code), val); 2989d4af9e69SDag-Erling Smørgrav } 2990d4af9e69SDag-Erling Smørgrav 2991d4af9e69SDag-Erling Smørgrav static void 2992557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val) 2993557f75e5SDag-Erling Smørgrav { 2994557f75e5SDag-Erling Smørgrav printf("%s 0%o\n", lookup_opcode_name(code), val); 2995557f75e5SDag-Erling Smørgrav } 2996557f75e5SDag-Erling Smørgrav 2997557f75e5SDag-Erling Smørgrav static void 2998d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val) 2999d4af9e69SDag-Erling Smørgrav { 3000d4af9e69SDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); 3001d4af9e69SDag-Erling Smørgrav } 3002d4af9e69SDag-Erling Smørgrav 3003d4af9e69SDag-Erling Smørgrav static void 3004d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val) 3005d4af9e69SDag-Erling Smørgrav { 3006bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), 3007bc5531deSDag-Erling Smørgrav val == NULL ? "none" : val); 3008d4af9e69SDag-Erling Smørgrav } 3009d4af9e69SDag-Erling Smørgrav 3010d4af9e69SDag-Erling Smørgrav static void 3011d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals) 3012d4af9e69SDag-Erling Smørgrav { 3013d4af9e69SDag-Erling Smørgrav u_int i; 3014d4af9e69SDag-Erling Smørgrav 3015d4af9e69SDag-Erling Smørgrav for (i = 0; i < count; i++) 3016d4af9e69SDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), vals[i]); 3017d4af9e69SDag-Erling Smørgrav } 3018d4af9e69SDag-Erling Smørgrav 3019e146993eSDag-Erling Smørgrav static void 3020e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals) 3021e146993eSDag-Erling Smørgrav { 3022e146993eSDag-Erling Smørgrav u_int i; 3023e146993eSDag-Erling Smørgrav 30244d3fc8b0SEd Maste switch (code) { 30254d3fc8b0SEd Maste case sAuthenticationMethods: 30264d3fc8b0SEd Maste case sChannelTimeout: 30274d3fc8b0SEd Maste break; 30284d3fc8b0SEd Maste default: 30294d3fc8b0SEd Maste if (count <= 0) 3030557f75e5SDag-Erling Smørgrav return; 30314d3fc8b0SEd Maste break; 30324d3fc8b0SEd Maste } 30334d3fc8b0SEd Maste 3034e146993eSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code)); 3035e146993eSDag-Erling Smørgrav for (i = 0; i < count; i++) 3036e146993eSDag-Erling Smørgrav printf(" %s", vals[i]); 3037076ad2f8SDag-Erling Smørgrav if (code == sAuthenticationMethods && count == 0) 3038076ad2f8SDag-Erling Smørgrav printf(" any"); 3039f374ba41SEd Maste else if (code == sChannelTimeout && count == 0) 3040f374ba41SEd Maste printf(" none"); 3041e146993eSDag-Erling Smørgrav printf("\n"); 3042e146993eSDag-Erling Smørgrav } 3043e146993eSDag-Erling Smørgrav 304447dd1d1bSDag-Erling Smørgrav static char * 304547dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la) 3046d4af9e69SDag-Erling Smørgrav { 304747dd1d1bSDag-Erling Smørgrav int r; 3048d4af9e69SDag-Erling Smørgrav struct addrinfo *ai; 304947dd1d1bSDag-Erling Smørgrav char addr[NI_MAXHOST], port[NI_MAXSERV]; 3050557f75e5SDag-Erling Smørgrav char *laddr1 = xstrdup(""), *laddr2 = NULL; 3051d4af9e69SDag-Erling Smørgrav 3052557f75e5SDag-Erling Smørgrav /* 3053557f75e5SDag-Erling Smørgrav * ListenAddress must be after Port. add_one_listen_addr pushes 3054557f75e5SDag-Erling Smørgrav * addresses onto a stack, so to maintain ordering we need to 3055557f75e5SDag-Erling Smørgrav * print these in reverse order. 3056557f75e5SDag-Erling Smørgrav */ 305747dd1d1bSDag-Erling Smørgrav for (ai = la->addrs; ai; ai = ai->ai_next) { 305847dd1d1bSDag-Erling Smørgrav if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, 3059d4af9e69SDag-Erling Smørgrav sizeof(addr), port, sizeof(port), 3060d4af9e69SDag-Erling Smørgrav NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { 306147dd1d1bSDag-Erling Smørgrav error("getnameinfo: %.100s", ssh_gai_strerror(r)); 306247dd1d1bSDag-Erling Smørgrav continue; 306347dd1d1bSDag-Erling Smørgrav } 3064557f75e5SDag-Erling Smørgrav laddr2 = laddr1; 306547dd1d1bSDag-Erling Smørgrav if (ai->ai_family == AF_INET6) { 306647dd1d1bSDag-Erling Smørgrav xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s", 306747dd1d1bSDag-Erling Smørgrav addr, port, 306847dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : " rdomain ", 306947dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : la->rdomain, 307047dd1d1bSDag-Erling Smørgrav laddr2); 307147dd1d1bSDag-Erling Smørgrav } else { 307247dd1d1bSDag-Erling Smørgrav xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s", 307347dd1d1bSDag-Erling Smørgrav addr, port, 307447dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : " rdomain ", 307547dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : la->rdomain, 307647dd1d1bSDag-Erling Smørgrav laddr2); 307747dd1d1bSDag-Erling Smørgrav } 3078557f75e5SDag-Erling Smørgrav free(laddr2); 3079d4af9e69SDag-Erling Smørgrav } 308047dd1d1bSDag-Erling Smørgrav return laddr1; 3081d4af9e69SDag-Erling Smørgrav } 308247dd1d1bSDag-Erling Smørgrav 308347dd1d1bSDag-Erling Smørgrav void 308447dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o) 308547dd1d1bSDag-Erling Smørgrav { 308647dd1d1bSDag-Erling Smørgrav char *s; 308747dd1d1bSDag-Erling Smørgrav u_int i; 308847dd1d1bSDag-Erling Smørgrav 308947dd1d1bSDag-Erling Smørgrav /* these are usually at the top of the config */ 309047dd1d1bSDag-Erling Smørgrav for (i = 0; i < o->num_ports; i++) 309147dd1d1bSDag-Erling Smørgrav printf("port %d\n", o->ports[i]); 309247dd1d1bSDag-Erling Smørgrav dump_cfg_fmtint(sAddressFamily, o->address_family); 309347dd1d1bSDag-Erling Smørgrav 309447dd1d1bSDag-Erling Smørgrav for (i = 0; i < o->num_listen_addrs; i++) { 309547dd1d1bSDag-Erling Smørgrav s = format_listen_addrs(&o->listen_addrs[i]); 309647dd1d1bSDag-Erling Smørgrav printf("%s", s); 309747dd1d1bSDag-Erling Smørgrav free(s); 309847dd1d1bSDag-Erling Smørgrav } 3099d4af9e69SDag-Erling Smørgrav 3100d4af9e69SDag-Erling Smørgrav /* integer arguments */ 3101cce7d346SDag-Erling Smørgrav #ifdef USE_PAM 3102557f75e5SDag-Erling Smørgrav dump_cfg_fmtint(sUsePAM, o->use_pam); 3103cce7d346SDag-Erling Smørgrav #endif 3104d4af9e69SDag-Erling Smørgrav dump_cfg_int(sLoginGraceTime, o->login_grace_time); 3105d4af9e69SDag-Erling Smørgrav dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); 3106d4af9e69SDag-Erling Smørgrav dump_cfg_int(sMaxAuthTries, o->max_authtries); 3107cce7d346SDag-Erling Smørgrav dump_cfg_int(sMaxSessions, o->max_sessions); 3108d4af9e69SDag-Erling Smørgrav dump_cfg_int(sClientAliveInterval, o->client_alive_interval); 3109d4af9e69SDag-Erling Smørgrav dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); 311038a52bd3SEd Maste dump_cfg_int(sRequiredRSASize, o->required_rsa_size); 3111557f75e5SDag-Erling Smørgrav dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask); 3112f374ba41SEd Maste dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout); 3113d4af9e69SDag-Erling Smørgrav 3114d4af9e69SDag-Erling Smørgrav /* formatted integer arguments */ 3115d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login); 3116d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts); 3117d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts); 3118d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication); 3119d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly, 3120d4af9e69SDag-Erling Smørgrav o->hostbased_uses_name_from_packet_only); 3121d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication); 3122cce7d346SDag-Erling Smørgrav #ifdef KRB5 3123d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication); 3124d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd); 3125d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup); 3126cce7d346SDag-Erling Smørgrav # ifdef USE_AFS 3127d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); 3128cce7d346SDag-Erling Smørgrav # endif 3129cce7d346SDag-Erling Smørgrav #endif 3130cce7d346SDag-Erling Smørgrav #ifdef GSSAPI 3131d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); 3132d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); 3133cce7d346SDag-Erling Smørgrav #endif 3134d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); 3135d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKbdInteractiveAuthentication, 3136d4af9e69SDag-Erling Smørgrav o->kbd_interactive_authentication); 3137d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPrintMotd, o->print_motd); 3138acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG 3139d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPrintLastLog, o->print_lastlog); 3140acc1a9efSDag-Erling Smørgrav #endif 3141d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding); 3142d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost); 3143f7167e0eSDag-Erling Smørgrav dump_cfg_fmtint(sPermitTTY, o->permit_tty); 3144a0ee8cc6SDag-Erling Smørgrav dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc); 3145d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sStrictModes, o->strict_modes); 3146d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive); 3147d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd); 3148d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sCompression, o->compression); 3149a0ee8cc6SDag-Erling Smørgrav dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); 3150d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sUseDNS, o->use_dns); 3151d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); 3152557f75e5SDag-Erling Smørgrav dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding); 3153ca86bcf2SDag-Erling Smørgrav dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding); 3154a0ee8cc6SDag-Erling Smørgrav dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); 3155076ad2f8SDag-Erling Smørgrav dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); 3156bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); 31574f52dfbbSDag-Erling Smørgrav dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info); 3158b2af61ecSKurt Lidl dump_cfg_fmtint(sUseBlacklist, o->use_blacklist); 3159d4af9e69SDag-Erling Smørgrav 3160d4af9e69SDag-Erling Smørgrav /* string arguments */ 3161d4af9e69SDag-Erling Smørgrav dump_cfg_string(sPidFile, o->pid_file); 316219261079SEd Maste dump_cfg_string(sModuliFile, o->moduli_file); 3163d4af9e69SDag-Erling Smørgrav dump_cfg_string(sXAuthLocation, o->xauth_location); 316419261079SEd Maste dump_cfg_string(sCiphers, o->ciphers); 316519261079SEd Maste dump_cfg_string(sMacs, o->macs); 3166d4af9e69SDag-Erling Smørgrav dump_cfg_string(sBanner, o->banner); 3167d4af9e69SDag-Erling Smørgrav dump_cfg_string(sForceCommand, o->adm_forced_command); 3168b15c8340SDag-Erling Smørgrav dump_cfg_string(sChrootDirectory, o->chroot_directory); 3169b15c8340SDag-Erling Smørgrav dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); 3170b15c8340SDag-Erling Smørgrav dump_cfg_string(sRevokedKeys, o->revoked_keys_file); 317119261079SEd Maste dump_cfg_string(sSecurityKeyProvider, o->sk_provider); 3172e2f6069cSDag-Erling Smørgrav dump_cfg_string(sAuthorizedPrincipalsFile, 3173e2f6069cSDag-Erling Smørgrav o->authorized_principals_file); 3174557f75e5SDag-Erling Smørgrav dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0' 3175557f75e5SDag-Erling Smørgrav ? "none" : o->version_addendum); 31766888a9beSDag-Erling Smørgrav dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); 31776888a9beSDag-Erling Smørgrav dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user); 3178557f75e5SDag-Erling Smørgrav dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command); 3179557f75e5SDag-Erling Smørgrav dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user); 3180e4a9863fSDag-Erling Smørgrav dump_cfg_string(sHostKeyAgent, o->host_key_agent); 318119261079SEd Maste dump_cfg_string(sKexAlgorithms, o->kex_algorithms); 318219261079SEd Maste dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms); 318319261079SEd Maste dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos); 318419261079SEd Maste dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms); 318519261079SEd Maste dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos); 318619261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN) 318747dd1d1bSDag-Erling Smørgrav dump_cfg_string(sRDomain, o->routing_domain); 318819261079SEd Maste #endif 3189d4af9e69SDag-Erling Smørgrav 3190d4af9e69SDag-Erling Smørgrav /* string arguments requiring a lookup */ 3191d4af9e69SDag-Erling Smørgrav dump_cfg_string(sLogLevel, log_level_name(o->log_level)); 3192d4af9e69SDag-Erling Smørgrav dump_cfg_string(sLogFacility, log_facility_name(o->log_facility)); 3193d4af9e69SDag-Erling Smørgrav 3194d4af9e69SDag-Erling Smørgrav /* string array arguments */ 3195e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files, 3196e146993eSDag-Erling Smørgrav o->authorized_keys_files); 3197d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, 3198d4af9e69SDag-Erling Smørgrav o->host_key_files); 3199557f75e5SDag-Erling Smørgrav dump_cfg_strarray(sHostCertificate, o->num_host_cert_files, 3200b15c8340SDag-Erling Smørgrav o->host_cert_files); 3201d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); 3202d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users); 3203d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups); 3204d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups); 3205d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env); 3206190cef3dSDag-Erling Smørgrav dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv); 32076888a9beSDag-Erling Smørgrav dump_cfg_strarray_oneline(sAuthenticationMethods, 32086888a9beSDag-Erling Smørgrav o->num_auth_methods, o->auth_methods); 320919261079SEd Maste dump_cfg_strarray_oneline(sLogVerbose, 321019261079SEd Maste o->num_log_verbose, o->log_verbose); 3211f374ba41SEd Maste dump_cfg_strarray_oneline(sChannelTimeout, 3212f374ba41SEd Maste o->num_channel_timeouts, o->channel_timeouts); 3213d4af9e69SDag-Erling Smørgrav 3214d4af9e69SDag-Erling Smørgrav /* other arguments */ 3215d4af9e69SDag-Erling Smørgrav for (i = 0; i < o->num_subsystems; i++) 3216d4af9e69SDag-Erling Smørgrav printf("subsystem %s %s\n", o->subsystem_name[i], 3217d4af9e69SDag-Erling Smørgrav o->subsystem_args[i]); 3218d4af9e69SDag-Erling Smørgrav 3219d4af9e69SDag-Erling Smørgrav printf("maxstartups %d:%d:%d\n", o->max_startups_begin, 3220d4af9e69SDag-Erling Smørgrav o->max_startups_rate, o->max_startups); 322119261079SEd Maste printf("persourcemaxstartups "); 322219261079SEd Maste if (o->per_source_max_startups == INT_MAX) 322319261079SEd Maste printf("none\n"); 322419261079SEd Maste else 322519261079SEd Maste printf("%d\n", o->per_source_max_startups); 322619261079SEd Maste printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4, 322719261079SEd Maste o->per_source_masklen_ipv6); 3228d4af9e69SDag-Erling Smørgrav 322947dd1d1bSDag-Erling Smørgrav s = NULL; 323047dd1d1bSDag-Erling Smørgrav for (i = 0; tunmode_desc[i].val != -1; i++) { 3231d4af9e69SDag-Erling Smørgrav if (tunmode_desc[i].val == o->permit_tun) { 3232d4af9e69SDag-Erling Smørgrav s = tunmode_desc[i].text; 3233d4af9e69SDag-Erling Smørgrav break; 3234d4af9e69SDag-Erling Smørgrav } 323547dd1d1bSDag-Erling Smørgrav } 3236d4af9e69SDag-Erling Smørgrav dump_cfg_string(sPermitTunnel, s); 3237d4af9e69SDag-Erling Smørgrav 3238e146993eSDag-Erling Smørgrav printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); 3239e146993eSDag-Erling Smørgrav printf("%s\n", iptos2str(o->ip_qos_bulk)); 32404a421b63SDag-Erling Smørgrav 3241acc1a9efSDag-Erling Smørgrav printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit, 3242e4a9863fSDag-Erling Smørgrav o->rekey_interval); 3243e4a9863fSDag-Erling Smørgrav 32444f52dfbbSDag-Erling Smørgrav printf("permitopen"); 32454f52dfbbSDag-Erling Smørgrav if (o->num_permitted_opens == 0) 32464f52dfbbSDag-Erling Smørgrav printf(" any"); 32474f52dfbbSDag-Erling Smørgrav else { 32484f52dfbbSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_opens; i++) 32494f52dfbbSDag-Erling Smørgrav printf(" %s", o->permitted_opens[i]); 32504f52dfbbSDag-Erling Smørgrav } 32514f52dfbbSDag-Erling Smørgrav printf("\n"); 3252190cef3dSDag-Erling Smørgrav printf("permitlisten"); 3253190cef3dSDag-Erling Smørgrav if (o->num_permitted_listens == 0) 3254190cef3dSDag-Erling Smørgrav printf(" any"); 3255190cef3dSDag-Erling Smørgrav else { 3256190cef3dSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_listens; i++) 3257190cef3dSDag-Erling Smørgrav printf(" %s", o->permitted_listens[i]); 3258190cef3dSDag-Erling Smørgrav } 3259190cef3dSDag-Erling Smørgrav printf("\n"); 3260190cef3dSDag-Erling Smørgrav 326119261079SEd Maste if (o->permit_user_env_allowlist == NULL) { 3262190cef3dSDag-Erling Smørgrav dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); 3263190cef3dSDag-Erling Smørgrav } else { 3264190cef3dSDag-Erling Smørgrav printf("permituserenvironment %s\n", 326519261079SEd Maste o->permit_user_env_allowlist); 3266190cef3dSDag-Erling Smørgrav } 3267190cef3dSDag-Erling Smørgrav 326819261079SEd Maste printf("pubkeyauthoptions"); 326919261079SEd Maste if (o->pubkey_auth_options == 0) 327019261079SEd Maste printf(" none"); 327119261079SEd Maste if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED) 327219261079SEd Maste printf(" touch-required"); 327319261079SEd Maste if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED) 327419261079SEd Maste printf(" verify-required"); 327519261079SEd Maste printf("\n"); 3276d4af9e69SDag-Erling Smørgrav } 3277