1*0ae642c7SEd Maste /* $OpenBSD: servconf.c,v 1.419 2024/09/25 01:24:04 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
730fdf8faeSEd Maste #if !defined(SSHD_PAM_SERVICE)
740fdf8faeSEd Maste # define SSHD_PAM_SERVICE "sshd"
750fdf8faeSEd Maste #endif
760fdf8faeSEd Maste
7747dd1d1bSDag-Erling Smørgrav static void add_listen_addr(ServerOptions *, const char *,
7847dd1d1bSDag-Erling Smørgrav const char *, int);
7947dd1d1bSDag-Erling Smørgrav static void add_one_listen_addr(ServerOptions *, const char *,
8047dd1d1bSDag-Erling Smørgrav const char *, int);
8119261079SEd Maste static void parse_server_config_depth(ServerOptions *options,
8219261079SEd Maste const char *filename, struct sshbuf *conf, struct include_list *includes,
8319261079SEd Maste struct connection_info *connectinfo, int flags, int *activep, int depth);
84ca3176e7SBrian Feldman
85190cef3dSDag-Erling Smørgrav extern struct sshbuf *cfg;
86511b41d2SMark Murray
87511b41d2SMark Murray /* Initializes the server options to their default values. */
88511b41d2SMark Murray
89511b41d2SMark Murray void
initialize_server_options(ServerOptions * options)90511b41d2SMark Murray initialize_server_options(ServerOptions *options)
91511b41d2SMark Murray {
92511b41d2SMark Murray memset(options, 0, sizeof(*options));
93989dd127SDag-Erling Smørgrav
94989dd127SDag-Erling Smørgrav /* Portable-specific options */
95cf2b5f3bSDag-Erling Smørgrav options->use_pam = -1;
960fdf8faeSEd Maste options->pam_service_name = NULL;
97989dd127SDag-Erling Smørgrav
98989dd127SDag-Erling Smørgrav /* Standard Options */
99511b41d2SMark Murray options->num_ports = 0;
100511b41d2SMark Murray options->ports_from_cmdline = 0;
101557f75e5SDag-Erling Smørgrav options->queued_listen_addrs = NULL;
102557f75e5SDag-Erling Smørgrav options->num_queued_listens = 0;
103511b41d2SMark Murray options->listen_addrs = NULL;
10447dd1d1bSDag-Erling Smørgrav options->num_listen_addrs = 0;
105aa49c926SDag-Erling Smørgrav options->address_family = -1;
10647dd1d1bSDag-Erling Smørgrav options->routing_domain = NULL;
107ca3176e7SBrian Feldman options->num_host_key_files = 0;
108b15c8340SDag-Erling Smørgrav options->num_host_cert_files = 0;
109e4a9863fSDag-Erling Smørgrav options->host_key_agent = NULL;
110e8aafc91SKris Kennaway options->pid_file = NULL;
111511b41d2SMark Murray options->login_grace_time = -1;
112ca3176e7SBrian Feldman options->permit_root_login = PERMIT_NOT_SET;
113511b41d2SMark Murray options->ignore_rhosts = -1;
114511b41d2SMark Murray options->ignore_user_known_hosts = -1;
115511b41d2SMark Murray options->print_motd = -1;
116ca3176e7SBrian Feldman options->print_lastlog = -1;
117511b41d2SMark Murray options->x11_forwarding = -1;
118511b41d2SMark Murray options->x11_display_offset = -1;
119af12a3e7SDag-Erling Smørgrav options->x11_use_localhost = -1;
120f7167e0eSDag-Erling Smørgrav options->permit_tty = -1;
121a0ee8cc6SDag-Erling Smørgrav options->permit_user_rc = -1;
122c2d3a559SKris Kennaway options->xauth_location = NULL;
123511b41d2SMark Murray options->strict_modes = -1;
1241ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = -1;
125af12a3e7SDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_NOT_SET;
126af12a3e7SDag-Erling Smørgrav options->log_level = SYSLOG_LEVEL_NOT_SET;
12719261079SEd Maste options->num_log_verbose = 0;
12819261079SEd Maste options->log_verbose = NULL;
129ca3176e7SBrian Feldman options->hostbased_authentication = -1;
130ca3176e7SBrian Feldman options->hostbased_uses_name_from_packet_only = -1;
13119261079SEd Maste options->hostbased_accepted_algos = NULL;
132eccfee6eSDag-Erling Smørgrav options->hostkeyalgorithms = NULL;
133ca3176e7SBrian Feldman options->pubkey_authentication = -1;
13419261079SEd Maste options->pubkey_auth_options = -1;
13519261079SEd Maste options->pubkey_accepted_algos = NULL;
136cb96ab36SAssar Westerlund options->kerberos_authentication = -1;
137af12a3e7SDag-Erling Smørgrav options->kerberos_or_local_passwd = -1;
138af12a3e7SDag-Erling Smørgrav options->kerberos_ticket_cleanup = -1;
1391ec0d754SDag-Erling Smørgrav options->kerberos_get_afs_token = -1;
140cf2b5f3bSDag-Erling Smørgrav options->gss_authentication=-1;
141cf2b5f3bSDag-Erling Smørgrav options->gss_cleanup_creds = -1;
142557f75e5SDag-Erling Smørgrav options->gss_strict_acceptor = -1;
143511b41d2SMark Murray options->password_authentication = -1;
14409958426SBrian Feldman options->kbd_interactive_authentication = -1;
145511b41d2SMark Murray options->permit_empty_passwd = -1;
146f388f5efSDag-Erling Smørgrav options->permit_user_env = -1;
14719261079SEd Maste options->permit_user_env_allowlist = NULL;
14880628bacSDag-Erling Smørgrav options->compression = -1;
149e4a9863fSDag-Erling Smørgrav options->rekey_limit = -1;
150e4a9863fSDag-Erling Smørgrav options->rekey_interval = -1;
15109958426SBrian Feldman options->allow_tcp_forwarding = -1;
152a0ee8cc6SDag-Erling Smørgrav options->allow_streamlocal_forwarding = -1;
153d4af9e69SDag-Erling Smørgrav options->allow_agent_forwarding = -1;
154511b41d2SMark Murray options->num_allow_users = 0;
155511b41d2SMark Murray options->num_deny_users = 0;
156511b41d2SMark Murray options->num_allow_groups = 0;
157511b41d2SMark Murray options->num_deny_groups = 0;
158e8aafc91SKris Kennaway options->ciphers = NULL;
159ca3176e7SBrian Feldman options->macs = NULL;
1604a421b63SDag-Erling Smørgrav options->kex_algorithms = NULL;
1612f513db7SEd Maste options->ca_sign_algorithms = NULL;
162a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = -1;
163a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
164a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = -1;
165c2d3a559SKris Kennaway options->num_subsystems = 0;
166c2d3a559SKris Kennaway options->max_startups_begin = -1;
167c2d3a559SKris Kennaway options->max_startups_rate = -1;
168c2d3a559SKris Kennaway options->max_startups = -1;
16919261079SEd Maste options->per_source_max_startups = -1;
17019261079SEd Maste options->per_source_masklen_ipv4 = -1;
17119261079SEd Maste options->per_source_masklen_ipv6 = -1;
1720fdf8faeSEd Maste options->per_source_penalty_exempt = NULL;
1730fdf8faeSEd Maste options->per_source_penalty.enabled = -1;
1740fdf8faeSEd Maste options->per_source_penalty.max_sources4 = -1;
1750fdf8faeSEd Maste options->per_source_penalty.max_sources6 = -1;
1760fdf8faeSEd Maste options->per_source_penalty.overflow_mode = -1;
1770fdf8faeSEd Maste options->per_source_penalty.overflow_mode6 = -1;
1780fdf8faeSEd Maste options->per_source_penalty.penalty_crash = -1;
1790fdf8faeSEd Maste options->per_source_penalty.penalty_authfail = -1;
1800fdf8faeSEd Maste options->per_source_penalty.penalty_noauth = -1;
1810fdf8faeSEd Maste options->per_source_penalty.penalty_grace = -1;
1823d9fd9fcSEd Maste options->per_source_penalty.penalty_refuseconnection = -1;
1830fdf8faeSEd Maste options->per_source_penalty.penalty_max = -1;
1840fdf8faeSEd Maste options->per_source_penalty.penalty_min = -1;
18521e764dfSDag-Erling Smørgrav options->max_authtries = -1;
186d4af9e69SDag-Erling Smørgrav options->max_sessions = -1;
187ca3176e7SBrian Feldman options->banner = NULL;
188cf2b5f3bSDag-Erling Smørgrav options->use_dns = -1;
189ca3176e7SBrian Feldman options->client_alive_interval = -1;
190ca3176e7SBrian Feldman options->client_alive_count_max = -1;
191e146993eSDag-Erling Smørgrav options->num_authkeys_files = 0;
19221e764dfSDag-Erling Smørgrav options->num_accept_env = 0;
193190cef3dSDag-Erling Smørgrav options->num_setenv = 0;
194b74df5b2SDag-Erling Smørgrav options->permit_tun = -1;
1954f52dfbbSDag-Erling Smørgrav options->permitted_opens = NULL;
196190cef3dSDag-Erling Smørgrav options->permitted_listens = NULL;
197333ee039SDag-Erling Smørgrav options->adm_forced_command = NULL;
198d4af9e69SDag-Erling Smørgrav options->chroot_directory = NULL;
1996888a9beSDag-Erling Smørgrav options->authorized_keys_command = NULL;
2006888a9beSDag-Erling Smørgrav options->authorized_keys_command_user = NULL;
201b15c8340SDag-Erling Smørgrav options->revoked_keys_file = NULL;
20219261079SEd Maste options->sk_provider = NULL;
203b15c8340SDag-Erling Smørgrav options->trusted_user_ca_keys = NULL;
204e2f6069cSDag-Erling Smørgrav options->authorized_principals_file = NULL;
205557f75e5SDag-Erling Smørgrav options->authorized_principals_command = NULL;
206557f75e5SDag-Erling Smørgrav options->authorized_principals_command_user = NULL;
2074a421b63SDag-Erling Smørgrav options->ip_qos_interactive = -1;
2084a421b63SDag-Erling Smørgrav options->ip_qos_bulk = -1;
209462c32cbSDag-Erling Smørgrav options->version_addendum = NULL;
210bc5531deSDag-Erling Smørgrav options->fingerprint_hash = -1;
211ca86bcf2SDag-Erling Smørgrav options->disable_forwarding = -1;
2124f52dfbbSDag-Erling Smørgrav options->expose_userauth_info = -1;
21338a52bd3SEd Maste options->required_rsa_size = -1;
214f374ba41SEd Maste options->channel_timeouts = NULL;
215f374ba41SEd Maste options->num_channel_timeouts = 0;
216f374ba41SEd Maste options->unused_connection_timeout = -1;
2170fdf8faeSEd Maste options->sshd_session_path = NULL;
2183d9fd9fcSEd Maste options->refuse_connection = -1;
219b2af61ecSKurt Lidl options->use_blacklist = -1;
220bc5531deSDag-Erling Smørgrav }
221bc5531deSDag-Erling Smørgrav
222bc5531deSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
223bc5531deSDag-Erling Smørgrav static int
option_clear_or_none(const char * o)224bc5531deSDag-Erling Smørgrav option_clear_or_none(const char *o)
225bc5531deSDag-Erling Smørgrav {
226bc5531deSDag-Erling Smørgrav return o == NULL || strcasecmp(o, "none") == 0;
227511b41d2SMark Murray }
228511b41d2SMark Murray
229acc1a9efSDag-Erling Smørgrav static void
assemble_algorithms(ServerOptions * o)230acc1a9efSDag-Erling Smørgrav assemble_algorithms(ServerOptions *o)
231acc1a9efSDag-Erling Smørgrav {
2322f513db7SEd Maste char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
23319261079SEd Maste char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
234190cef3dSDag-Erling Smørgrav int r;
235190cef3dSDag-Erling Smørgrav
236190cef3dSDag-Erling Smørgrav all_cipher = cipher_alg_list(',', 0);
237190cef3dSDag-Erling Smørgrav all_mac = mac_alg_list(',');
238190cef3dSDag-Erling Smørgrav all_kex = kex_alg_list(',');
239190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ',');
2402f513db7SEd Maste all_sig = sshkey_alg_list(0, 1, 1, ',');
24119261079SEd Maste /* remove unsupported algos from default lists */
24219261079SEd Maste def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
24319261079SEd Maste def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
24419261079SEd Maste def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
24519261079SEd Maste def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
24619261079SEd Maste def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
247190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
248190cef3dSDag-Erling Smørgrav do { \
249190cef3dSDag-Erling Smørgrav if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
25019261079SEd Maste fatal_fr(r, "%s", #what); \
251190cef3dSDag-Erling Smørgrav } while (0)
25219261079SEd Maste ASSEMBLE(ciphers, def_cipher, all_cipher);
25319261079SEd Maste ASSEMBLE(macs, def_mac, all_mac);
25419261079SEd Maste ASSEMBLE(kex_algorithms, def_kex, all_kex);
25519261079SEd Maste ASSEMBLE(hostkeyalgorithms, def_key, all_key);
25619261079SEd Maste ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
25719261079SEd Maste ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
25819261079SEd Maste ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
259190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
260190cef3dSDag-Erling Smørgrav free(all_cipher);
261190cef3dSDag-Erling Smørgrav free(all_mac);
262190cef3dSDag-Erling Smørgrav free(all_kex);
263190cef3dSDag-Erling Smørgrav free(all_key);
2642f513db7SEd Maste free(all_sig);
26519261079SEd Maste free(def_cipher);
26619261079SEd Maste free(def_mac);
26719261079SEd Maste free(def_kex);
26819261079SEd Maste free(def_key);
26919261079SEd Maste free(def_sig);
27047dd1d1bSDag-Erling Smørgrav }
27147dd1d1bSDag-Erling Smørgrav
27247dd1d1bSDag-Erling Smørgrav static const char *defaultkey = "[default]";
27347dd1d1bSDag-Erling Smørgrav
27447dd1d1bSDag-Erling Smørgrav void
servconf_add_hostkey(const char * file,const int line,ServerOptions * options,const char * path,int userprovided)27547dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(const char *file, const int line,
27619261079SEd Maste ServerOptions *options, const char *path, int userprovided)
27747dd1d1bSDag-Erling Smørgrav {
27847dd1d1bSDag-Erling Smørgrav char *apath = derelativise_path(path);
27947dd1d1bSDag-Erling Smørgrav
28047dd1d1bSDag-Erling Smørgrav if (file == defaultkey && access(path, R_OK) != 0)
28147dd1d1bSDag-Erling Smørgrav return;
28219261079SEd Maste opt_array_append2(file, line, "HostKey",
28319261079SEd Maste &options->host_key_files, &options->host_key_file_userprovided,
28419261079SEd Maste &options->num_host_key_files, apath, userprovided);
28547dd1d1bSDag-Erling Smørgrav free(apath);
28647dd1d1bSDag-Erling Smørgrav }
28747dd1d1bSDag-Erling Smørgrav
28847dd1d1bSDag-Erling Smørgrav void
servconf_add_hostcert(const char * file,const int line,ServerOptions * options,const char * path)28947dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(const char *file, const int line,
29047dd1d1bSDag-Erling Smørgrav ServerOptions *options, const char *path)
29147dd1d1bSDag-Erling Smørgrav {
29247dd1d1bSDag-Erling Smørgrav char *apath = derelativise_path(path);
29347dd1d1bSDag-Erling Smørgrav
29419261079SEd Maste opt_array_append(file, line, "HostCertificate",
29547dd1d1bSDag-Erling Smørgrav &options->host_cert_files, &options->num_host_cert_files, apath);
29647dd1d1bSDag-Erling Smørgrav free(apath);
29747dd1d1bSDag-Erling Smørgrav }
29847dd1d1bSDag-Erling Smørgrav
299511b41d2SMark Murray void
fill_default_server_options(ServerOptions * options)300511b41d2SMark Murray fill_default_server_options(ServerOptions *options)
301511b41d2SMark Murray {
30247dd1d1bSDag-Erling Smørgrav u_int i;
303bc5531deSDag-Erling Smørgrav
304989dd127SDag-Erling Smørgrav /* Portable-specific options */
305cf2b5f3bSDag-Erling Smørgrav if (options->use_pam == -1)
306f0477b26SDag-Erling Smørgrav options->use_pam = 1;
3070fdf8faeSEd Maste if (options->pam_service_name == NULL)
3080fdf8faeSEd Maste options->pam_service_name = xstrdup(SSHD_PAM_SERVICE);
309989dd127SDag-Erling Smørgrav
310989dd127SDag-Erling Smørgrav /* Standard Options */
311ca3176e7SBrian Feldman if (options->num_host_key_files == 0) {
312ca3176e7SBrian Feldman /* fill default hostkeys for protocols */
31347dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options,
31419261079SEd Maste _PATH_HOST_RSA_KEY_FILE, 0);
3154a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
31647dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options,
31719261079SEd Maste _PATH_HOST_ECDSA_KEY_FILE, 0);
3184a421b63SDag-Erling Smørgrav #endif
31947dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options,
32019261079SEd Maste _PATH_HOST_ED25519_KEY_FILE, 0);
32147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
32247dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(defaultkey, 0, options,
32319261079SEd Maste _PATH_HOST_XMSS_KEY_FILE, 0);
32447dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
325af12a3e7SDag-Erling Smørgrav }
326144a80bdSDag-Erling Smørgrav if (options->num_host_key_files == 0)
327144a80bdSDag-Erling Smørgrav fatal("No host key files found");
328b15c8340SDag-Erling Smørgrav /* No certificates by default */
329511b41d2SMark Murray if (options->num_ports == 0)
330511b41d2SMark Murray options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
331557f75e5SDag-Erling Smørgrav if (options->address_family == -1)
332557f75e5SDag-Erling Smørgrav options->address_family = AF_UNSPEC;
333511b41d2SMark Murray if (options->listen_addrs == NULL)
33447dd1d1bSDag-Erling Smørgrav add_listen_addr(options, NULL, NULL, 0);
335e8aafc91SKris Kennaway if (options->pid_file == NULL)
336bc5531deSDag-Erling Smørgrav options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
33719261079SEd Maste if (options->moduli_file == NULL)
33819261079SEd Maste options->moduli_file = xstrdup(_PATH_DH_MODULI);
339511b41d2SMark Murray if (options->login_grace_time == -1)
340975616f0SDag-Erling Smørgrav options->login_grace_time = 120;
341ca3176e7SBrian Feldman if (options->permit_root_login == PERMIT_NOT_SET)
342975616f0SDag-Erling Smørgrav options->permit_root_login = PERMIT_NO;
343511b41d2SMark Murray if (options->ignore_rhosts == -1)
344fe5fd017SMark Murray options->ignore_rhosts = 1;
345511b41d2SMark Murray if (options->ignore_user_known_hosts == -1)
346511b41d2SMark Murray options->ignore_user_known_hosts = 0;
347511b41d2SMark Murray if (options->print_motd == -1)
348511b41d2SMark Murray options->print_motd = 1;
349ca3176e7SBrian Feldman if (options->print_lastlog == -1)
350ca3176e7SBrian Feldman options->print_lastlog = 1;
351511b41d2SMark Murray if (options->x11_forwarding == -1)
35277934b7aSEd Maste options->x11_forwarding = 0;
353511b41d2SMark Murray if (options->x11_display_offset == -1)
354fe5fd017SMark Murray options->x11_display_offset = 10;
355af12a3e7SDag-Erling Smørgrav if (options->x11_use_localhost == -1)
356af12a3e7SDag-Erling Smørgrav options->x11_use_localhost = 1;
357c2d3a559SKris Kennaway if (options->xauth_location == NULL)
358bc5531deSDag-Erling Smørgrav options->xauth_location = xstrdup(_PATH_XAUTH);
359f7167e0eSDag-Erling Smørgrav if (options->permit_tty == -1)
360f7167e0eSDag-Erling Smørgrav options->permit_tty = 1;
361a0ee8cc6SDag-Erling Smørgrav if (options->permit_user_rc == -1)
362a0ee8cc6SDag-Erling Smørgrav options->permit_user_rc = 1;
363511b41d2SMark Murray if (options->strict_modes == -1)
364511b41d2SMark Murray options->strict_modes = 1;
3651ec0d754SDag-Erling Smørgrav if (options->tcp_keep_alive == -1)
3661ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = 1;
367af12a3e7SDag-Erling Smørgrav if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
368511b41d2SMark Murray options->log_facility = SYSLOG_FACILITY_AUTH;
369af12a3e7SDag-Erling Smørgrav if (options->log_level == SYSLOG_LEVEL_NOT_SET)
370511b41d2SMark Murray options->log_level = SYSLOG_LEVEL_INFO;
371ca3176e7SBrian Feldman if (options->hostbased_authentication == -1)
372ca3176e7SBrian Feldman options->hostbased_authentication = 0;
373ca3176e7SBrian Feldman if (options->hostbased_uses_name_from_packet_only == -1)
374ca3176e7SBrian Feldman options->hostbased_uses_name_from_packet_only = 0;
375ca3176e7SBrian Feldman if (options->pubkey_authentication == -1)
376ca3176e7SBrian Feldman options->pubkey_authentication = 1;
37719261079SEd Maste if (options->pubkey_auth_options == -1)
37819261079SEd Maste options->pubkey_auth_options = 0;
379989dd127SDag-Erling Smørgrav if (options->kerberos_authentication == -1)
380cf2b5f3bSDag-Erling Smørgrav options->kerberos_authentication = 0;
381af12a3e7SDag-Erling Smørgrav if (options->kerberos_or_local_passwd == -1)
382af12a3e7SDag-Erling Smørgrav options->kerberos_or_local_passwd = 1;
383af12a3e7SDag-Erling Smørgrav if (options->kerberos_ticket_cleanup == -1)
384af12a3e7SDag-Erling Smørgrav options->kerberos_ticket_cleanup = 1;
3851ec0d754SDag-Erling Smørgrav if (options->kerberos_get_afs_token == -1)
3861ec0d754SDag-Erling Smørgrav options->kerberos_get_afs_token = 0;
387cf2b5f3bSDag-Erling Smørgrav if (options->gss_authentication == -1)
388cf2b5f3bSDag-Erling Smørgrav options->gss_authentication = 0;
389cf2b5f3bSDag-Erling Smørgrav if (options->gss_cleanup_creds == -1)
390cf2b5f3bSDag-Erling Smørgrav options->gss_cleanup_creds = 1;
391557f75e5SDag-Erling Smørgrav if (options->gss_strict_acceptor == -1)
392d93a896eSDag-Erling Smørgrav options->gss_strict_acceptor = 1;
393511b41d2SMark Murray if (options->password_authentication == -1)
394b909c84bSDag-Erling Smørgrav options->password_authentication = 0;
39509958426SBrian Feldman if (options->kbd_interactive_authentication == -1)
39619261079SEd Maste options->kbd_interactive_authentication = 1;
397511b41d2SMark Murray if (options->permit_empty_passwd == -1)
398fe5fd017SMark Murray options->permit_empty_passwd = 0;
399190cef3dSDag-Erling Smørgrav if (options->permit_user_env == -1) {
400f388f5efSDag-Erling Smørgrav options->permit_user_env = 0;
40119261079SEd Maste options->permit_user_env_allowlist = NULL;
402190cef3dSDag-Erling Smørgrav }
40380628bacSDag-Erling Smørgrav if (options->compression == -1)
40419261079SEd Maste #ifdef WITH_ZLIB
405d4ecd108SDag-Erling Smørgrav options->compression = COMP_DELAYED;
40619261079SEd Maste #else
40719261079SEd Maste options->compression = COMP_NONE;
40819261079SEd Maste #endif
40919261079SEd Maste
410e4a9863fSDag-Erling Smørgrav if (options->rekey_limit == -1)
411e4a9863fSDag-Erling Smørgrav options->rekey_limit = 0;
412e4a9863fSDag-Erling Smørgrav if (options->rekey_interval == -1)
413e4a9863fSDag-Erling Smørgrav options->rekey_interval = 0;
41409958426SBrian Feldman if (options->allow_tcp_forwarding == -1)
4156888a9beSDag-Erling Smørgrav options->allow_tcp_forwarding = FORWARD_ALLOW;
416a0ee8cc6SDag-Erling Smørgrav if (options->allow_streamlocal_forwarding == -1)
417a0ee8cc6SDag-Erling Smørgrav options->allow_streamlocal_forwarding = FORWARD_ALLOW;
418d4af9e69SDag-Erling Smørgrav if (options->allow_agent_forwarding == -1)
419d4af9e69SDag-Erling Smørgrav options->allow_agent_forwarding = 1;
420a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.gateway_ports == -1)
421a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = 0;
422c2d3a559SKris Kennaway if (options->max_startups == -1)
4236888a9beSDag-Erling Smørgrav options->max_startups = 100;
424c2d3a559SKris Kennaway if (options->max_startups_rate == -1)
4256888a9beSDag-Erling Smørgrav options->max_startups_rate = 30; /* 30% */
426c2d3a559SKris Kennaway if (options->max_startups_begin == -1)
4276888a9beSDag-Erling Smørgrav options->max_startups_begin = 10;
42819261079SEd Maste if (options->per_source_max_startups == -1)
42919261079SEd Maste options->per_source_max_startups = INT_MAX;
43019261079SEd Maste if (options->per_source_masklen_ipv4 == -1)
43119261079SEd Maste options->per_source_masklen_ipv4 = 32;
43219261079SEd Maste if (options->per_source_masklen_ipv6 == -1)
43319261079SEd Maste options->per_source_masklen_ipv6 = 128;
4340fdf8faeSEd Maste if (options->per_source_penalty.enabled == -1)
4350fdf8faeSEd Maste options->per_source_penalty.enabled = 1;
4360fdf8faeSEd Maste if (options->per_source_penalty.max_sources4 == -1)
4370fdf8faeSEd Maste options->per_source_penalty.max_sources4 = 65536;
4380fdf8faeSEd Maste if (options->per_source_penalty.max_sources6 == -1)
4390fdf8faeSEd Maste options->per_source_penalty.max_sources6 = 65536;
4400fdf8faeSEd Maste if (options->per_source_penalty.overflow_mode == -1)
4410fdf8faeSEd Maste options->per_source_penalty.overflow_mode = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
4420fdf8faeSEd Maste if (options->per_source_penalty.overflow_mode6 == -1)
4430fdf8faeSEd Maste options->per_source_penalty.overflow_mode6 = options->per_source_penalty.overflow_mode;
4440fdf8faeSEd Maste if (options->per_source_penalty.penalty_crash == -1)
4450fdf8faeSEd Maste options->per_source_penalty.penalty_crash = 90;
4460fdf8faeSEd Maste if (options->per_source_penalty.penalty_grace == -1)
4473d9fd9fcSEd Maste options->per_source_penalty.penalty_grace = 10;
4480fdf8faeSEd Maste if (options->per_source_penalty.penalty_authfail == -1)
4490fdf8faeSEd Maste options->per_source_penalty.penalty_authfail = 5;
4500fdf8faeSEd Maste if (options->per_source_penalty.penalty_noauth == -1)
4510fdf8faeSEd Maste options->per_source_penalty.penalty_noauth = 1;
4523d9fd9fcSEd Maste if (options->per_source_penalty.penalty_refuseconnection == -1)
4533d9fd9fcSEd Maste options->per_source_penalty.penalty_refuseconnection = 10;
4540fdf8faeSEd Maste if (options->per_source_penalty.penalty_min == -1)
4550fdf8faeSEd Maste options->per_source_penalty.penalty_min = 15;
4560fdf8faeSEd Maste if (options->per_source_penalty.penalty_max == -1)
4570fdf8faeSEd Maste options->per_source_penalty.penalty_max = 600;
45821e764dfSDag-Erling Smørgrav if (options->max_authtries == -1)
45921e764dfSDag-Erling Smørgrav options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
460d4af9e69SDag-Erling Smørgrav if (options->max_sessions == -1)
461d4af9e69SDag-Erling Smørgrav options->max_sessions = DEFAULT_SESSIONS_MAX;
462cf2b5f3bSDag-Erling Smørgrav if (options->use_dns == -1)
463c4cd1fa4SDag-Erling Smørgrav options->use_dns = 1;
464ca3176e7SBrian Feldman if (options->client_alive_interval == -1)
465ca3176e7SBrian Feldman options->client_alive_interval = 0;
466ca3176e7SBrian Feldman if (options->client_alive_count_max == -1)
467ca3176e7SBrian Feldman options->client_alive_count_max = 3;
468e146993eSDag-Erling Smørgrav if (options->num_authkeys_files == 0) {
46919261079SEd Maste opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
47047dd1d1bSDag-Erling Smørgrav &options->authorized_keys_files,
47147dd1d1bSDag-Erling Smørgrav &options->num_authkeys_files,
47247dd1d1bSDag-Erling Smørgrav _PATH_SSH_USER_PERMITTED_KEYS);
47319261079SEd Maste opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
47447dd1d1bSDag-Erling Smørgrav &options->authorized_keys_files,
47547dd1d1bSDag-Erling Smørgrav &options->num_authkeys_files,
47647dd1d1bSDag-Erling Smørgrav _PATH_SSH_USER_PERMITTED_KEYS2);
477af12a3e7SDag-Erling Smørgrav }
478b74df5b2SDag-Erling Smørgrav if (options->permit_tun == -1)
479b74df5b2SDag-Erling Smørgrav options->permit_tun = SSH_TUNMODE_NO;
4804a421b63SDag-Erling Smørgrav if (options->ip_qos_interactive == -1)
481190cef3dSDag-Erling Smørgrav options->ip_qos_interactive = IPTOS_DSCP_AF21;
4824a421b63SDag-Erling Smørgrav if (options->ip_qos_bulk == -1)
483190cef3dSDag-Erling Smørgrav options->ip_qos_bulk = IPTOS_DSCP_CS1;
484462c32cbSDag-Erling Smørgrav if (options->version_addendum == NULL)
485462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
486a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
487a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = 0177;
488a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_unlink == -1)
489a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = 0;
490bc5531deSDag-Erling Smørgrav if (options->fingerprint_hash == -1)
491bc5531deSDag-Erling Smørgrav options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
492ca86bcf2SDag-Erling Smørgrav if (options->disable_forwarding == -1)
493ca86bcf2SDag-Erling Smørgrav options->disable_forwarding = 0;
4944f52dfbbSDag-Erling Smørgrav if (options->expose_userauth_info == -1)
4954f52dfbbSDag-Erling Smørgrav options->expose_userauth_info = 0;
49619261079SEd Maste if (options->sk_provider == NULL)
49719261079SEd Maste options->sk_provider = xstrdup("internal");
49838a52bd3SEd Maste if (options->required_rsa_size == -1)
49938a52bd3SEd Maste options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
500f374ba41SEd Maste if (options->unused_connection_timeout == -1)
501f374ba41SEd Maste options->unused_connection_timeout = 0;
5020fdf8faeSEd Maste if (options->sshd_session_path == NULL)
5030fdf8faeSEd Maste options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION);
5043d9fd9fcSEd Maste if (options->refuse_connection == -1)
5053d9fd9fcSEd Maste options->refuse_connection = 0;
506b2af61ecSKurt Lidl if (options->use_blacklist == -1)
507b2af61ecSKurt Lidl options->use_blacklist = 0;
508eccfee6eSDag-Erling Smørgrav
509acc1a9efSDag-Erling Smørgrav assemble_algorithms(options);
510eccfee6eSDag-Erling Smørgrav
511bc5531deSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
512bc5531deSDag-Erling Smørgrav do { \
513bc5531deSDag-Erling Smørgrav if (option_clear_or_none(v)) { \
514bc5531deSDag-Erling Smørgrav free(v); \
515bc5531deSDag-Erling Smørgrav v = NULL; \
516bc5531deSDag-Erling Smørgrav } \
517bc5531deSDag-Erling Smørgrav } while(0)
518f374ba41SEd Maste #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
519f374ba41SEd Maste do { \
520f374ba41SEd Maste if (options->nv == 1 && \
521f374ba41SEd Maste strcasecmp(options->v[0], none) == 0) { \
522f374ba41SEd Maste free(options->v[0]); \
523f374ba41SEd Maste free(options->v); \
524f374ba41SEd Maste options->v = NULL; \
525f374ba41SEd Maste options->nv = 0; \
526f374ba41SEd Maste } \
527f374ba41SEd Maste } while (0)
528bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->pid_file);
529bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->xauth_location);
530bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->banner);
531bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->trusted_user_ca_keys);
532bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->revoked_keys_file);
53319261079SEd Maste CLEAR_ON_NONE(options->sk_provider);
534557f75e5SDag-Erling Smørgrav CLEAR_ON_NONE(options->authorized_principals_file);
535acc1a9efSDag-Erling Smørgrav CLEAR_ON_NONE(options->adm_forced_command);
536acc1a9efSDag-Erling Smørgrav CLEAR_ON_NONE(options->chroot_directory);
53747dd1d1bSDag-Erling Smørgrav CLEAR_ON_NONE(options->routing_domain);
53819261079SEd Maste CLEAR_ON_NONE(options->host_key_agent);
5390fdf8faeSEd Maste CLEAR_ON_NONE(options->per_source_penalty_exempt);
540f374ba41SEd Maste
541bc5531deSDag-Erling Smørgrav for (i = 0; i < options->num_host_key_files; i++)
542bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->host_key_files[i]);
543bc5531deSDag-Erling Smørgrav for (i = 0; i < options->num_host_cert_files; i++)
544bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->host_cert_files[i]);
545bc5531deSDag-Erling Smørgrav
546f374ba41SEd Maste CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
547f374ba41SEd Maste CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
548f374ba41SEd Maste #undef CLEAR_ON_NONE
549f374ba41SEd Maste #undef CLEAR_ON_NONE_ARRAY
550511b41d2SMark Murray }
551511b41d2SMark Murray
552511b41d2SMark Murray /* Keyword tokens. */
553511b41d2SMark Murray typedef enum {
554511b41d2SMark Murray sBadOption, /* == unknown option */
555989dd127SDag-Erling Smørgrav /* Portable-specific options */
5560fdf8faeSEd Maste sUsePAM, sPAMServiceName,
557989dd127SDag-Erling Smørgrav /* Standard Options */
558ca86bcf2SDag-Erling Smørgrav sPort, sHostKeyFile, sLoginGraceTime,
55919261079SEd Maste sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
560af12a3e7SDag-Erling Smørgrav sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
561e9e8876aSEd Maste sKerberosGetAFSToken, sPasswordAuthentication,
562e9e8876aSEd Maste sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
563ca3176e7SBrian Feldman sPrintMotd, sPrintLastLog, sIgnoreRhosts,
564af12a3e7SDag-Erling Smørgrav sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
565f7167e0eSDag-Erling Smørgrav sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
566ca86bcf2SDag-Erling Smørgrav sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
567e4a9863fSDag-Erling Smørgrav sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
56819261079SEd Maste sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
56919261079SEd Maste sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
570bc5531deSDag-Erling Smørgrav sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
571cf2b5f3bSDag-Erling Smørgrav sBanner, sUseDNS, sHostbasedAuthentication,
57219261079SEd Maste sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
57319261079SEd Maste sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
5740fdf8faeSEd Maste sPerSourcePenalties, sPerSourcePenaltyExemptList,
575bc5531deSDag-Erling Smørgrav sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
576557f75e5SDag-Erling Smørgrav sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
577190cef3dSDag-Erling Smørgrav sAcceptEnv, sSetEnv, sPermitTunnel,
578190cef3dSDag-Erling Smørgrav sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
579d4af9e69SDag-Erling Smørgrav sUsePrivilegeSeparation, sAllowAgentForwarding,
58019261079SEd Maste sHostCertificate, sInclude,
581e2f6069cSDag-Erling Smørgrav sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
582557f75e5SDag-Erling Smørgrav sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
5832f513db7SEd Maste sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
5846888a9beSDag-Erling Smørgrav sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
585a0ee8cc6SDag-Erling Smørgrav sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
586a0ee8cc6SDag-Erling Smørgrav sStreamLocalBindMask, sStreamLocalBindUnlink,
587ca86bcf2SDag-Erling Smørgrav sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
58819261079SEd Maste sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
589f374ba41SEd Maste sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
5903d9fd9fcSEd Maste sSshdSessionPath, sRefuseConnection,
591b2af61ecSKurt Lidl sUseBlacklist,
592ca86bcf2SDag-Erling Smørgrav sDeprecated, sIgnore, sUnsupported
593511b41d2SMark Murray } ServerOpCodes;
594511b41d2SMark Murray
59519261079SEd Maste #define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */
596333ee039SDag-Erling Smørgrav #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
597333ee039SDag-Erling Smørgrav #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
59819261079SEd Maste #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */
59919261079SEd Maste #define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */
600333ee039SDag-Erling Smørgrav
601511b41d2SMark Murray /* Textual representation of the tokens. */
602511b41d2SMark Murray static struct {
603511b41d2SMark Murray const char *name;
604511b41d2SMark Murray ServerOpCodes opcode;
605333ee039SDag-Erling Smørgrav u_int flags;
606511b41d2SMark Murray } keywords[] = {
607989dd127SDag-Erling Smørgrav /* Portable-specific options */
608cf2b5f3bSDag-Erling Smørgrav #ifdef USE_PAM
609333ee039SDag-Erling Smørgrav { "usepam", sUsePAM, SSHCFG_GLOBAL },
6100fdf8faeSEd Maste { "pamservicename", sPAMServiceName, SSHCFG_ALL },
611cf2b5f3bSDag-Erling Smørgrav #else
612333ee039SDag-Erling Smørgrav { "usepam", sUnsupported, SSHCFG_GLOBAL },
6130fdf8faeSEd Maste { "pamservicename", sUnsupported, SSHCFG_ALL },
614975616f0SDag-Erling Smørgrav #endif
615333ee039SDag-Erling Smørgrav { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
616989dd127SDag-Erling Smørgrav /* Standard Options */
617333ee039SDag-Erling Smørgrav { "port", sPort, SSHCFG_GLOBAL },
618333ee039SDag-Erling Smørgrav { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
619333ee039SDag-Erling Smørgrav { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
620e4a9863fSDag-Erling Smørgrav { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
621333ee039SDag-Erling Smørgrav { "pidfile", sPidFile, SSHCFG_GLOBAL },
62219261079SEd Maste { "modulifile", sModuliFile, SSHCFG_GLOBAL },
623ca86bcf2SDag-Erling Smørgrav { "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
624333ee039SDag-Erling Smørgrav { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
625ca86bcf2SDag-Erling Smørgrav { "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
626d4af9e69SDag-Erling Smørgrav { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
627333ee039SDag-Erling Smørgrav { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
6284f52dfbbSDag-Erling Smørgrav { "loglevel", sLogLevel, SSHCFG_ALL },
62919261079SEd Maste { "logverbose", sLogVerbose, SSHCFG_ALL },
630333ee039SDag-Erling Smørgrav { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
631ca86bcf2SDag-Erling Smørgrav { "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
632d4af9e69SDag-Erling Smørgrav { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
633e2f6069cSDag-Erling Smørgrav { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
63419261079SEd Maste { "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
63519261079SEd Maste { "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
636eccfee6eSDag-Erling Smørgrav { "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
637ca86bcf2SDag-Erling Smørgrav { "rsaauthentication", sDeprecated, SSHCFG_ALL },
638d4af9e69SDag-Erling Smørgrav { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
63919261079SEd Maste { "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
64019261079SEd Maste { "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
64119261079SEd Maste { "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
642333ee039SDag-Erling Smørgrav { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
643cf2b5f3bSDag-Erling Smørgrav #ifdef KRB5
644d4af9e69SDag-Erling Smørgrav { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
645333ee039SDag-Erling Smørgrav { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
646333ee039SDag-Erling Smørgrav { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
6471ec0d754SDag-Erling Smørgrav #ifdef USE_AFS
648333ee039SDag-Erling Smørgrav { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
6491ec0d754SDag-Erling Smørgrav #else
650333ee039SDag-Erling Smørgrav { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
6511ec0d754SDag-Erling Smørgrav #endif
652cf2b5f3bSDag-Erling Smørgrav #else
653d4af9e69SDag-Erling Smørgrav { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
654333ee039SDag-Erling Smørgrav { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
655333ee039SDag-Erling Smørgrav { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
656333ee039SDag-Erling Smørgrav { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
657cb96ab36SAssar Westerlund #endif
658333ee039SDag-Erling Smørgrav { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
659333ee039SDag-Erling Smørgrav { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
660cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
661d4af9e69SDag-Erling Smørgrav { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
662333ee039SDag-Erling Smørgrav { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
663557f75e5SDag-Erling Smørgrav { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
664cf2b5f3bSDag-Erling Smørgrav #else
665d4af9e69SDag-Erling Smørgrav { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
666333ee039SDag-Erling Smørgrav { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
667557f75e5SDag-Erling Smørgrav { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
668511b41d2SMark Murray #endif
669d4af9e69SDag-Erling Smørgrav { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
670d4af9e69SDag-Erling Smørgrav { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
67119261079SEd Maste { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
67219261079SEd Maste { "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
673333ee039SDag-Erling Smørgrav { "checkmail", sDeprecated, SSHCFG_GLOBAL },
674333ee039SDag-Erling Smørgrav { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
675333ee039SDag-Erling Smørgrav { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
676333ee039SDag-Erling Smørgrav { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
677acc1a9efSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG
678acc1a9efSDag-Erling Smørgrav { "printlastlog", sUnsupported, SSHCFG_GLOBAL },
679acc1a9efSDag-Erling Smørgrav #else
680333ee039SDag-Erling Smørgrav { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
681acc1a9efSDag-Erling Smørgrav #endif
68219261079SEd Maste { "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
683333ee039SDag-Erling Smørgrav { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
684333ee039SDag-Erling Smørgrav { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
685333ee039SDag-Erling Smørgrav { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
686333ee039SDag-Erling Smørgrav { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
687333ee039SDag-Erling Smørgrav { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
688333ee039SDag-Erling Smørgrav { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
689cce7d346SDag-Erling Smørgrav { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
690333ee039SDag-Erling Smørgrav { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
691ca86bcf2SDag-Erling Smørgrav { "uselogin", sDeprecated, SSHCFG_GLOBAL },
692333ee039SDag-Erling Smørgrav { "compression", sCompression, SSHCFG_GLOBAL },
693e4a9863fSDag-Erling Smørgrav { "rekeylimit", sRekeyLimit, SSHCFG_ALL },
694333ee039SDag-Erling Smørgrav { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
695333ee039SDag-Erling Smørgrav { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
696333ee039SDag-Erling Smørgrav { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
697d4af9e69SDag-Erling Smørgrav { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
698462c32cbSDag-Erling Smørgrav { "allowusers", sAllowUsers, SSHCFG_ALL },
699462c32cbSDag-Erling Smørgrav { "denyusers", sDenyUsers, SSHCFG_ALL },
700462c32cbSDag-Erling Smørgrav { "allowgroups", sAllowGroups, SSHCFG_ALL },
701462c32cbSDag-Erling Smørgrav { "denygroups", sDenyGroups, SSHCFG_ALL },
702333ee039SDag-Erling Smørgrav { "ciphers", sCiphers, SSHCFG_GLOBAL },
703333ee039SDag-Erling Smørgrav { "macs", sMacs, SSHCFG_GLOBAL },
704ca86bcf2SDag-Erling Smørgrav { "protocol", sIgnore, SSHCFG_GLOBAL },
705333ee039SDag-Erling Smørgrav { "gatewayports", sGatewayPorts, SSHCFG_ALL },
706edf85781SEd Maste { "subsystem", sSubsystem, SSHCFG_ALL },
707333ee039SDag-Erling Smørgrav { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
70819261079SEd Maste { "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
70919261079SEd Maste { "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
7100fdf8faeSEd Maste { "persourcepenalties", sPerSourcePenalties, SSHCFG_GLOBAL },
7110fdf8faeSEd Maste { "persourcepenaltyexemptlist", sPerSourcePenaltyExemptList, SSHCFG_GLOBAL },
712d4af9e69SDag-Erling Smørgrav { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
713d4af9e69SDag-Erling Smørgrav { "maxsessions", sMaxSessions, SSHCFG_ALL },
714d4af9e69SDag-Erling Smørgrav { "banner", sBanner, SSHCFG_ALL },
715333ee039SDag-Erling Smørgrav { "usedns", sUseDNS, SSHCFG_GLOBAL },
716333ee039SDag-Erling Smørgrav { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
717333ee039SDag-Erling Smørgrav { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
718ca86bcf2SDag-Erling Smørgrav { "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
719ca86bcf2SDag-Erling Smørgrav { "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
720e2f6069cSDag-Erling Smørgrav { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
721e146993eSDag-Erling Smørgrav { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
722d93a896eSDag-Erling Smørgrav { "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
723462c32cbSDag-Erling Smørgrav { "acceptenv", sAcceptEnv, SSHCFG_ALL },
724190cef3dSDag-Erling Smørgrav { "setenv", sSetEnv, SSHCFG_ALL },
725e2f6069cSDag-Erling Smørgrav { "permittunnel", sPermitTunnel, SSHCFG_ALL },
726f7167e0eSDag-Erling Smørgrav { "permittty", sPermitTTY, SSHCFG_ALL },
727a0ee8cc6SDag-Erling Smørgrav { "permituserrc", sPermitUserRC, SSHCFG_ALL },
728333ee039SDag-Erling Smørgrav { "match", sMatch, SSHCFG_ALL },
729333ee039SDag-Erling Smørgrav { "permitopen", sPermitOpen, SSHCFG_ALL },
730190cef3dSDag-Erling Smørgrav { "permitlisten", sPermitListen, SSHCFG_ALL },
731333ee039SDag-Erling Smørgrav { "forcecommand", sForceCommand, SSHCFG_ALL },
732d4af9e69SDag-Erling Smørgrav { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
733b15c8340SDag-Erling Smørgrav { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
734b15c8340SDag-Erling Smørgrav { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
735b15c8340SDag-Erling Smørgrav { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
736e2f6069cSDag-Erling Smørgrav { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
7374a421b63SDag-Erling Smørgrav { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
73819261079SEd Maste { "include", sInclude, SSHCFG_ALL },
7394a421b63SDag-Erling Smørgrav { "ipqos", sIPQoS, SSHCFG_ALL },
7406888a9beSDag-Erling Smørgrav { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
7416888a9beSDag-Erling Smørgrav { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
742557f75e5SDag-Erling Smørgrav { "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
743557f75e5SDag-Erling Smørgrav { "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
744462c32cbSDag-Erling Smørgrav { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
7456888a9beSDag-Erling Smørgrav { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
746a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
747a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
748a0ee8cc6SDag-Erling Smørgrav { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
749bc5531deSDag-Erling Smørgrav { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
750ca86bcf2SDag-Erling Smørgrav { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
7514f52dfbbSDag-Erling Smørgrav { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
75247dd1d1bSDag-Erling Smørgrav { "rdomain", sRDomain, SSHCFG_ALL },
7532f513db7SEd Maste { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
75419261079SEd Maste { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
75538a52bd3SEd Maste { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
756f374ba41SEd Maste { "channeltimeout", sChannelTimeout, SSHCFG_ALL },
757f374ba41SEd Maste { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
7580fdf8faeSEd Maste { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL },
7593d9fd9fcSEd Maste { "refuseconnection", sRefuseConnection, SSHCFG_ALL },
760b2af61ecSKurt Lidl { "useblacklist", sUseBlacklist, SSHCFG_GLOBAL },
761e426c743SEd Maste { "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */
762a93cbba2SEd Maste
763333ee039SDag-Erling Smørgrav { NULL, sBadOption, 0 }
764511b41d2SMark Murray };
765511b41d2SMark Murray
766d4af9e69SDag-Erling Smørgrav static struct {
767d4af9e69SDag-Erling Smørgrav int val;
768d4af9e69SDag-Erling Smørgrav char *text;
769d4af9e69SDag-Erling Smørgrav } tunmode_desc[] = {
770d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_NO, "no" },
771d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_POINTOPOINT, "point-to-point" },
772d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_ETHERNET, "ethernet" },
773d4af9e69SDag-Erling Smørgrav { SSH_TUNMODE_YES, "yes" },
774d4af9e69SDag-Erling Smørgrav { -1, NULL }
775d4af9e69SDag-Erling Smørgrav };
776d4af9e69SDag-Erling Smørgrav
777190cef3dSDag-Erling Smørgrav /* Returns an opcode name from its number */
778190cef3dSDag-Erling Smørgrav
779190cef3dSDag-Erling Smørgrav static const char *
lookup_opcode_name(ServerOpCodes code)780190cef3dSDag-Erling Smørgrav lookup_opcode_name(ServerOpCodes code)
781190cef3dSDag-Erling Smørgrav {
782190cef3dSDag-Erling Smørgrav u_int i;
783190cef3dSDag-Erling Smørgrav
784190cef3dSDag-Erling Smørgrav for (i = 0; keywords[i].name != NULL; i++)
785190cef3dSDag-Erling Smørgrav if (keywords[i].opcode == code)
786190cef3dSDag-Erling Smørgrav return(keywords[i].name);
787190cef3dSDag-Erling Smørgrav return "UNKNOWN";
788190cef3dSDag-Erling Smørgrav }
789190cef3dSDag-Erling Smørgrav
790190cef3dSDag-Erling Smørgrav
791511b41d2SMark Murray /*
792ca3176e7SBrian Feldman * Returns the number of the token pointed to by cp or sBadOption.
793511b41d2SMark Murray */
794511b41d2SMark Murray
795511b41d2SMark Murray static ServerOpCodes
parse_token(const char * cp,const char * filename,int linenum,u_int * flags)796511b41d2SMark Murray parse_token(const char *cp, const char *filename,
797333ee039SDag-Erling Smørgrav int linenum, u_int *flags)
798511b41d2SMark Murray {
799ca3176e7SBrian Feldman u_int i;
800511b41d2SMark Murray
801511b41d2SMark Murray for (i = 0; keywords[i].name; i++)
802333ee039SDag-Erling Smørgrav if (strcasecmp(cp, keywords[i].name) == 0) {
803333ee039SDag-Erling Smørgrav *flags = keywords[i].flags;
804511b41d2SMark Murray return keywords[i].opcode;
805333ee039SDag-Erling Smørgrav }
806511b41d2SMark Murray
807ca3176e7SBrian Feldman error("%s: line %d: Bad configuration option: %s",
808511b41d2SMark Murray filename, linenum, cp);
809511b41d2SMark Murray return sBadOption;
810511b41d2SMark Murray }
811511b41d2SMark Murray
812b15c8340SDag-Erling Smørgrav char *
derelativise_path(const char * path)813b15c8340SDag-Erling Smørgrav derelativise_path(const char *path)
814b15c8340SDag-Erling Smørgrav {
815bc5531deSDag-Erling Smørgrav char *expanded, *ret, cwd[PATH_MAX];
816b15c8340SDag-Erling Smørgrav
817bc5531deSDag-Erling Smørgrav if (strcasecmp(path, "none") == 0)
818bc5531deSDag-Erling Smørgrav return xstrdup("none");
819b15c8340SDag-Erling Smørgrav expanded = tilde_expand_filename(path, getuid());
82019261079SEd Maste if (path_absolute(expanded))
821b15c8340SDag-Erling Smørgrav return expanded;
8228ad9b54aSDag-Erling Smørgrav if (getcwd(cwd, sizeof(cwd)) == NULL)
82319261079SEd Maste fatal_f("getcwd: %s", strerror(errno));
824b15c8340SDag-Erling Smørgrav xasprintf(&ret, "%s/%s", cwd, expanded);
825e4a9863fSDag-Erling Smørgrav free(expanded);
826b15c8340SDag-Erling Smørgrav return ret;
827b15c8340SDag-Erling Smørgrav }
828b15c8340SDag-Erling Smørgrav
829af12a3e7SDag-Erling Smørgrav static void
add_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)83047dd1d1bSDag-Erling Smørgrav add_listen_addr(ServerOptions *options, const char *addr,
83147dd1d1bSDag-Erling Smørgrav const char *rdomain, int port)
832511b41d2SMark Murray {
833d4ecd108SDag-Erling Smørgrav u_int i;
834511b41d2SMark Murray
83547dd1d1bSDag-Erling Smørgrav if (port > 0)
83647dd1d1bSDag-Erling Smørgrav add_one_listen_addr(options, addr, rdomain, port);
83747dd1d1bSDag-Erling Smørgrav else {
83847dd1d1bSDag-Erling Smørgrav for (i = 0; i < options->num_ports; i++) {
83947dd1d1bSDag-Erling Smørgrav add_one_listen_addr(options, addr, rdomain,
84047dd1d1bSDag-Erling Smørgrav options->ports[i]);
84147dd1d1bSDag-Erling Smørgrav }
84247dd1d1bSDag-Erling Smørgrav }
843ca3176e7SBrian Feldman }
844ca3176e7SBrian Feldman
845af12a3e7SDag-Erling Smørgrav static void
add_one_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)84647dd1d1bSDag-Erling Smørgrav add_one_listen_addr(ServerOptions *options, const char *addr,
84747dd1d1bSDag-Erling Smørgrav const char *rdomain, int port)
848ca3176e7SBrian Feldman {
849ca3176e7SBrian Feldman struct addrinfo hints, *ai, *aitop;
850ca3176e7SBrian Feldman char strport[NI_MAXSERV];
851ca3176e7SBrian Feldman int gaierr;
85247dd1d1bSDag-Erling Smørgrav u_int i;
85347dd1d1bSDag-Erling Smørgrav
85447dd1d1bSDag-Erling Smørgrav /* Find listen_addrs entry for this rdomain */
85547dd1d1bSDag-Erling Smørgrav for (i = 0; i < options->num_listen_addrs; i++) {
85647dd1d1bSDag-Erling Smørgrav if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
85747dd1d1bSDag-Erling Smørgrav break;
85847dd1d1bSDag-Erling Smørgrav if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
85947dd1d1bSDag-Erling Smørgrav continue;
86047dd1d1bSDag-Erling Smørgrav if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
86147dd1d1bSDag-Erling Smørgrav break;
86247dd1d1bSDag-Erling Smørgrav }
86347dd1d1bSDag-Erling Smørgrav if (i >= options->num_listen_addrs) {
86447dd1d1bSDag-Erling Smørgrav /* No entry for this rdomain; allocate one */
86547dd1d1bSDag-Erling Smørgrav if (i >= INT_MAX)
86619261079SEd Maste fatal_f("too many listen addresses");
86747dd1d1bSDag-Erling Smørgrav options->listen_addrs = xrecallocarray(options->listen_addrs,
86847dd1d1bSDag-Erling Smørgrav options->num_listen_addrs, options->num_listen_addrs + 1,
86947dd1d1bSDag-Erling Smørgrav sizeof(*options->listen_addrs));
87047dd1d1bSDag-Erling Smørgrav i = options->num_listen_addrs++;
87147dd1d1bSDag-Erling Smørgrav if (rdomain != NULL)
87247dd1d1bSDag-Erling Smørgrav options->listen_addrs[i].rdomain = xstrdup(rdomain);
87347dd1d1bSDag-Erling Smørgrav }
87447dd1d1bSDag-Erling Smørgrav /* options->listen_addrs[i] points to the addresses for this rdomain */
875ca3176e7SBrian Feldman
876511b41d2SMark Murray memset(&hints, 0, sizeof(hints));
877aa49c926SDag-Erling Smørgrav hints.ai_family = options->address_family;
878511b41d2SMark Murray hints.ai_socktype = SOCK_STREAM;
879511b41d2SMark Murray hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
880cce7d346SDag-Erling Smørgrav snprintf(strport, sizeof strport, "%d", port);
881511b41d2SMark Murray if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
882ca3176e7SBrian Feldman fatal("bad addr or host: %s (%s)",
883511b41d2SMark Murray addr ? addr : "<NULL>",
884d4af9e69SDag-Erling Smørgrav ssh_gai_strerror(gaierr));
885511b41d2SMark Murray for (ai = aitop; ai->ai_next; ai = ai->ai_next)
886511b41d2SMark Murray ;
88747dd1d1bSDag-Erling Smørgrav ai->ai_next = options->listen_addrs[i].addrs;
88847dd1d1bSDag-Erling Smørgrav options->listen_addrs[i].addrs = aitop;
88947dd1d1bSDag-Erling Smørgrav }
89047dd1d1bSDag-Erling Smørgrav
89147dd1d1bSDag-Erling Smørgrav /* Returns nonzero if the routing domain name is valid */
89247dd1d1bSDag-Erling Smørgrav static int
valid_rdomain(const char * name)89347dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name)
89447dd1d1bSDag-Erling Smørgrav {
89547dd1d1bSDag-Erling Smørgrav #if defined(HAVE_SYS_VALID_RDOMAIN)
89647dd1d1bSDag-Erling Smørgrav return sys_valid_rdomain(name);
89747dd1d1bSDag-Erling Smørgrav #elif defined(__OpenBSD__)
89847dd1d1bSDag-Erling Smørgrav const char *errstr;
89947dd1d1bSDag-Erling Smørgrav long long num;
90047dd1d1bSDag-Erling Smørgrav struct rt_tableinfo info;
90147dd1d1bSDag-Erling Smørgrav int mib[6];
90247dd1d1bSDag-Erling Smørgrav size_t miblen = sizeof(mib);
90347dd1d1bSDag-Erling Smørgrav
90447dd1d1bSDag-Erling Smørgrav if (name == NULL)
90547dd1d1bSDag-Erling Smørgrav return 1;
90647dd1d1bSDag-Erling Smørgrav
90747dd1d1bSDag-Erling Smørgrav num = strtonum(name, 0, 255, &errstr);
90847dd1d1bSDag-Erling Smørgrav if (errstr != NULL)
90947dd1d1bSDag-Erling Smørgrav return 0;
91047dd1d1bSDag-Erling Smørgrav
91147dd1d1bSDag-Erling Smørgrav /* Check whether the table actually exists */
91247dd1d1bSDag-Erling Smørgrav memset(mib, 0, sizeof(mib));
91347dd1d1bSDag-Erling Smørgrav mib[0] = CTL_NET;
91447dd1d1bSDag-Erling Smørgrav mib[1] = PF_ROUTE;
91547dd1d1bSDag-Erling Smørgrav mib[4] = NET_RT_TABLE;
91647dd1d1bSDag-Erling Smørgrav mib[5] = (int)num;
91747dd1d1bSDag-Erling Smørgrav if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
91847dd1d1bSDag-Erling Smørgrav return 0;
91947dd1d1bSDag-Erling Smørgrav
92047dd1d1bSDag-Erling Smørgrav return 1;
92147dd1d1bSDag-Erling Smørgrav #else /* defined(__OpenBSD__) */
92247dd1d1bSDag-Erling Smørgrav error("Routing domains are not supported on this platform");
92347dd1d1bSDag-Erling Smørgrav return 0;
92447dd1d1bSDag-Erling Smørgrav #endif
925511b41d2SMark Murray }
926511b41d2SMark Murray
927557f75e5SDag-Erling Smørgrav /*
928557f75e5SDag-Erling Smørgrav * Queue a ListenAddress to be processed once we have all of the Ports
929557f75e5SDag-Erling Smørgrav * and AddressFamily options.
930557f75e5SDag-Erling Smørgrav */
931557f75e5SDag-Erling Smørgrav static void
queue_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)93247dd1d1bSDag-Erling Smørgrav queue_listen_addr(ServerOptions *options, const char *addr,
93347dd1d1bSDag-Erling Smørgrav const char *rdomain, int port)
934557f75e5SDag-Erling Smørgrav {
93547dd1d1bSDag-Erling Smørgrav struct queued_listenaddr *qla;
93647dd1d1bSDag-Erling Smørgrav
93747dd1d1bSDag-Erling Smørgrav options->queued_listen_addrs = xrecallocarray(
93847dd1d1bSDag-Erling Smørgrav options->queued_listen_addrs,
93947dd1d1bSDag-Erling Smørgrav options->num_queued_listens, options->num_queued_listens + 1,
94047dd1d1bSDag-Erling Smørgrav sizeof(*options->queued_listen_addrs));
94147dd1d1bSDag-Erling Smørgrav qla = &options->queued_listen_addrs[options->num_queued_listens++];
94247dd1d1bSDag-Erling Smørgrav qla->addr = xstrdup(addr);
94347dd1d1bSDag-Erling Smørgrav qla->port = port;
94447dd1d1bSDag-Erling Smørgrav qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
945557f75e5SDag-Erling Smørgrav }
946557f75e5SDag-Erling Smørgrav
947557f75e5SDag-Erling Smørgrav /*
948557f75e5SDag-Erling Smørgrav * Process queued (text) ListenAddress entries.
949557f75e5SDag-Erling Smørgrav */
950557f75e5SDag-Erling Smørgrav static void
process_queued_listen_addrs(ServerOptions * options)951557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(ServerOptions *options)
952557f75e5SDag-Erling Smørgrav {
953557f75e5SDag-Erling Smørgrav u_int i;
95447dd1d1bSDag-Erling Smørgrav struct queued_listenaddr *qla;
955557f75e5SDag-Erling Smørgrav
956557f75e5SDag-Erling Smørgrav if (options->num_ports == 0)
957557f75e5SDag-Erling Smørgrav options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
958557f75e5SDag-Erling Smørgrav if (options->address_family == -1)
959557f75e5SDag-Erling Smørgrav options->address_family = AF_UNSPEC;
960557f75e5SDag-Erling Smørgrav
961557f75e5SDag-Erling Smørgrav for (i = 0; i < options->num_queued_listens; i++) {
96247dd1d1bSDag-Erling Smørgrav qla = &options->queued_listen_addrs[i];
96347dd1d1bSDag-Erling Smørgrav add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
96447dd1d1bSDag-Erling Smørgrav free(qla->addr);
96547dd1d1bSDag-Erling Smørgrav free(qla->rdomain);
966557f75e5SDag-Erling Smørgrav }
967557f75e5SDag-Erling Smørgrav free(options->queued_listen_addrs);
968557f75e5SDag-Erling Smørgrav options->queued_listen_addrs = NULL;
969557f75e5SDag-Erling Smørgrav options->num_queued_listens = 0;
970557f75e5SDag-Erling Smørgrav }
971557f75e5SDag-Erling Smørgrav
9724f52dfbbSDag-Erling Smørgrav /*
973333ee039SDag-Erling Smørgrav * The strategy for the Match blocks is that the config file is parsed twice.
974333ee039SDag-Erling Smørgrav *
975333ee039SDag-Erling Smørgrav * The first time is at startup. activep is initialized to 1 and the
976333ee039SDag-Erling Smørgrav * directives in the global context are processed and acted on. Hitting a
977333ee039SDag-Erling Smørgrav * Match directive unsets activep and the directives inside the block are
978333ee039SDag-Erling Smørgrav * checked for syntax only.
979333ee039SDag-Erling Smørgrav *
980333ee039SDag-Erling Smørgrav * The second time is after a connection has been established but before
981333ee039SDag-Erling Smørgrav * authentication. activep is initialized to 2 and global config directives
982333ee039SDag-Erling Smørgrav * are ignored since they have already been processed. If the criteria in a
983333ee039SDag-Erling Smørgrav * Match block is met, activep is set and the subsequent directives
984333ee039SDag-Erling Smørgrav * processed and actioned until EOF or another Match block unsets it. Any
985333ee039SDag-Erling Smørgrav * options set are copied into the main server config.
986333ee039SDag-Erling Smørgrav *
987333ee039SDag-Erling Smørgrav * Potential additions/improvements:
988ca86bcf2SDag-Erling Smørgrav * - Add Match support for pre-kex directives, eg. Ciphers.
989333ee039SDag-Erling Smørgrav *
990333ee039SDag-Erling Smørgrav * - Add a Tag directive (idea from David Leonard) ala pf, eg:
991333ee039SDag-Erling Smørgrav * Match Address 192.168.0.*
992333ee039SDag-Erling Smørgrav * Tag trusted
993333ee039SDag-Erling Smørgrav * Match Group wheel
994333ee039SDag-Erling Smørgrav * Tag trusted
995333ee039SDag-Erling Smørgrav * Match Tag trusted
996333ee039SDag-Erling Smørgrav * AllowTcpForwarding yes
997333ee039SDag-Erling Smørgrav * GatewayPorts clientspecified
998333ee039SDag-Erling Smørgrav * [...]
999333ee039SDag-Erling Smørgrav *
1000333ee039SDag-Erling Smørgrav * - Add a PermittedChannelRequests directive
1001333ee039SDag-Erling Smørgrav * Match Group shell
1002333ee039SDag-Erling Smørgrav * PermittedChannelRequests session,forwarded-tcpip
1003333ee039SDag-Erling Smørgrav */
1004333ee039SDag-Erling Smørgrav
1005333ee039SDag-Erling Smørgrav static int
match_cfg_line_group(const char * grps,int line,const char * user)1006333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user)
1007333ee039SDag-Erling Smørgrav {
1008333ee039SDag-Erling Smørgrav int result = 0;
1009333ee039SDag-Erling Smørgrav struct passwd *pw;
1010333ee039SDag-Erling Smørgrav
1011333ee039SDag-Erling Smørgrav if (user == NULL)
1012333ee039SDag-Erling Smørgrav goto out;
1013333ee039SDag-Erling Smørgrav
1014333ee039SDag-Erling Smørgrav if ((pw = getpwnam(user)) == NULL) {
1015333ee039SDag-Erling Smørgrav debug("Can't match group at line %d because user %.100s does "
1016333ee039SDag-Erling Smørgrav "not exist", line, user);
1017333ee039SDag-Erling Smørgrav } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1018333ee039SDag-Erling Smørgrav debug("Can't Match group because user %.100s not in any group "
1019333ee039SDag-Erling Smørgrav "at line %d", user, line);
1020d4af9e69SDag-Erling Smørgrav } else if (ga_match_pattern_list(grps) != 1) {
1021d4af9e69SDag-Erling Smørgrav debug("user %.100s does not match group list %.100s at line %d",
1022d4af9e69SDag-Erling Smørgrav user, grps, line);
1023333ee039SDag-Erling Smørgrav } else {
1024d4af9e69SDag-Erling Smørgrav debug("user %.100s matched group list %.100s at line %d", user,
1025d4af9e69SDag-Erling Smørgrav grps, line);
1026333ee039SDag-Erling Smørgrav result = 1;
1027333ee039SDag-Erling Smørgrav }
1028333ee039SDag-Erling Smørgrav out:
1029333ee039SDag-Erling Smørgrav ga_free();
1030333ee039SDag-Erling Smørgrav return result;
1031333ee039SDag-Erling Smørgrav }
1032333ee039SDag-Erling Smørgrav
103347dd1d1bSDag-Erling Smørgrav static void
match_test_missing_fatal(const char * criteria,const char * attrib)103447dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib)
103547dd1d1bSDag-Erling Smørgrav {
103647dd1d1bSDag-Erling Smørgrav fatal("'Match %s' in configuration but '%s' not in connection "
103747dd1d1bSDag-Erling Smørgrav "test specification.", criteria, attrib);
103847dd1d1bSDag-Erling Smørgrav }
103947dd1d1bSDag-Erling Smørgrav
1040462c32cbSDag-Erling Smørgrav /*
10416888a9beSDag-Erling Smørgrav * All of the attributes on a single Match line are ANDed together, so we need
1042f7167e0eSDag-Erling Smørgrav * to check every attribute and set the result to zero if any attribute does
10436888a9beSDag-Erling Smørgrav * not match.
1044462c32cbSDag-Erling Smørgrav */
1045333ee039SDag-Erling Smørgrav static int
match_cfg_line(const char * full_line,int * acp,char *** avp,int line,struct connection_info * ci)10463d9fd9fcSEd Maste match_cfg_line(const char *full_line, int *acp, char ***avp,
10473d9fd9fcSEd Maste int line, struct connection_info *ci)
1048333ee039SDag-Erling Smørgrav {
1049f7167e0eSDag-Erling Smørgrav int result = 1, attributes = 0, port;
1050*0ae642c7SEd Maste char *arg, *attrib = NULL, *oattrib;
1051333ee039SDag-Erling Smørgrav
1052462c32cbSDag-Erling Smørgrav if (ci == NULL)
10533d9fd9fcSEd Maste debug3("checking syntax for 'Match %s'", full_line);
10543d9fd9fcSEd Maste else {
10553d9fd9fcSEd Maste debug3("checking match for '%s' user %s%s host %s addr %s "
10563d9fd9fcSEd Maste "laddr %s lport %d", full_line,
10573d9fd9fcSEd Maste ci->user ? ci->user : "(null)",
10583d9fd9fcSEd Maste ci->user_invalid ? " (invalid)" : "",
1059462c32cbSDag-Erling Smørgrav ci->host ? ci->host : "(null)",
1060462c32cbSDag-Erling Smørgrav ci->address ? ci->address : "(null)",
1061462c32cbSDag-Erling Smørgrav ci->laddress ? ci->laddress : "(null)", ci->lport);
10623d9fd9fcSEd Maste }
1063333ee039SDag-Erling Smørgrav
1064*0ae642c7SEd Maste while ((oattrib = argv_next(acp, avp)) != NULL) {
1065*0ae642c7SEd Maste attrib = xstrdup(oattrib);
106619261079SEd Maste /* Terminate on comment */
106719261079SEd Maste if (*attrib == '#') {
10683d9fd9fcSEd Maste argv_consume(acp); /* mark all arguments consumed */
106919261079SEd Maste break;
107019261079SEd Maste }
107119261079SEd Maste arg = NULL;
1072f7167e0eSDag-Erling Smørgrav attributes++;
107319261079SEd Maste /* Criterion "all" has no argument and must appear alone */
1074f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "all") == 0) {
10753d9fd9fcSEd Maste if (attributes > 1 ||
10763d9fd9fcSEd Maste ((arg = argv_next(acp, avp)) != NULL &&
107719261079SEd Maste *arg != '\0' && *arg != '#')) {
1078f7167e0eSDag-Erling Smørgrav error("'all' cannot be combined with other "
1079f7167e0eSDag-Erling Smørgrav "Match attributes");
1080*0ae642c7SEd Maste result = -1;
1081*0ae642c7SEd Maste goto out;
1082f7167e0eSDag-Erling Smørgrav }
108319261079SEd Maste if (arg != NULL && *arg == '#')
10843d9fd9fcSEd Maste argv_consume(acp); /* consume remaining args */
1085*0ae642c7SEd Maste result = 1;
1086*0ae642c7SEd Maste goto out;
1087f7167e0eSDag-Erling Smørgrav }
10883d9fd9fcSEd Maste /* Criterion "invalid-user" also has no argument */
10893d9fd9fcSEd Maste if (strcasecmp(attrib, "invalid-user") == 0) {
1090*0ae642c7SEd Maste if (ci == NULL) {
1091*0ae642c7SEd Maste result = 0;
10923d9fd9fcSEd Maste continue;
1093*0ae642c7SEd Maste }
10943d9fd9fcSEd Maste if (ci->user_invalid == 0)
10953d9fd9fcSEd Maste result = 0;
10963d9fd9fcSEd Maste else
10973d9fd9fcSEd Maste debug("matched invalid-user at line %d", line);
10983d9fd9fcSEd Maste continue;
10993d9fd9fcSEd Maste }
1100*0ae642c7SEd Maste
1101*0ae642c7SEd Maste /* Keep this list in sync with below */
1102*0ae642c7SEd Maste if (strprefix(attrib, "user=", 1) != NULL ||
1103*0ae642c7SEd Maste strprefix(attrib, "group=", 1) != NULL ||
1104*0ae642c7SEd Maste strprefix(attrib, "host=", 1) != NULL ||
1105*0ae642c7SEd Maste strprefix(attrib, "address=", 1) != NULL ||
1106*0ae642c7SEd Maste strprefix(attrib, "localaddress=", 1) != NULL ||
1107*0ae642c7SEd Maste strprefix(attrib, "localport=", 1) != NULL ||
1108*0ae642c7SEd Maste strprefix(attrib, "rdomain=", 1) != NULL) {
1109*0ae642c7SEd Maste arg = strchr(attrib, '=');
1110*0ae642c7SEd Maste *(arg++) = '\0';
1111*0ae642c7SEd Maste } else {
1112*0ae642c7SEd Maste arg = argv_next(acp, avp);
1113*0ae642c7SEd Maste }
1114*0ae642c7SEd Maste
111519261079SEd Maste /* All other criteria require an argument */
1116*0ae642c7SEd Maste if (arg == NULL || *arg == '\0' || *arg == '#') {
1117333ee039SDag-Erling Smørgrav error("Missing Match criteria for %s", attrib);
1118*0ae642c7SEd Maste result = -1;
1119*0ae642c7SEd Maste goto out;
1120333ee039SDag-Erling Smørgrav }
1121333ee039SDag-Erling Smørgrav if (strcasecmp(attrib, "user") == 0) {
112219261079SEd Maste if (ci == NULL || (ci->test && ci->user == NULL)) {
1123333ee039SDag-Erling Smørgrav result = 0;
1124333ee039SDag-Erling Smørgrav continue;
1125333ee039SDag-Erling Smørgrav }
112647dd1d1bSDag-Erling Smørgrav if (ci->user == NULL)
112747dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("User", "user");
112819261079SEd Maste if (match_usergroup_pattern_list(ci->user, arg) != 1)
1129333ee039SDag-Erling Smørgrav result = 0;
1130333ee039SDag-Erling Smørgrav else
1131333ee039SDag-Erling Smørgrav debug("user %.100s matched 'User %.100s' at "
1132462c32cbSDag-Erling Smørgrav "line %d", ci->user, arg, line);
1133333ee039SDag-Erling Smørgrav } else if (strcasecmp(attrib, "group") == 0) {
113419261079SEd Maste if (ci == NULL || (ci->test && ci->user == NULL)) {
1135462c32cbSDag-Erling Smørgrav result = 0;
1136462c32cbSDag-Erling Smørgrav continue;
1137462c32cbSDag-Erling Smørgrav }
113847dd1d1bSDag-Erling Smørgrav if (ci->user == NULL)
113947dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("Group", "user");
1140462c32cbSDag-Erling Smørgrav switch (match_cfg_line_group(arg, line, ci->user)) {
1141333ee039SDag-Erling Smørgrav case -1:
1142*0ae642c7SEd Maste result = -1;
1143*0ae642c7SEd Maste goto out;
1144333ee039SDag-Erling Smørgrav case 0:
1145333ee039SDag-Erling Smørgrav result = 0;
1146333ee039SDag-Erling Smørgrav }
1147333ee039SDag-Erling Smørgrav } else if (strcasecmp(attrib, "host") == 0) {
114819261079SEd Maste if (ci == NULL || (ci->test && ci->host == NULL)) {
1149333ee039SDag-Erling Smørgrav result = 0;
1150333ee039SDag-Erling Smørgrav continue;
1151333ee039SDag-Erling Smørgrav }
115247dd1d1bSDag-Erling Smørgrav if (ci->host == NULL)
115347dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("Host", "host");
1154557f75e5SDag-Erling Smørgrav if (match_hostname(ci->host, arg) != 1)
1155333ee039SDag-Erling Smørgrav result = 0;
1156333ee039SDag-Erling Smørgrav else
1157333ee039SDag-Erling Smørgrav debug("connection from %.100s matched 'Host "
1158462c32cbSDag-Erling Smørgrav "%.100s' at line %d", ci->host, arg, line);
1159333ee039SDag-Erling Smørgrav } else if (strcasecmp(attrib, "address") == 0) {
116019261079SEd Maste if (ci == NULL || (ci->test && ci->address == NULL)) {
116119261079SEd Maste if (addr_match_list(NULL, arg) != 0)
116219261079SEd Maste fatal("Invalid Match address argument "
116319261079SEd Maste "'%s' at line %d", arg, line);
1164462c32cbSDag-Erling Smørgrav result = 0;
1165462c32cbSDag-Erling Smørgrav continue;
1166462c32cbSDag-Erling Smørgrav }
116747dd1d1bSDag-Erling Smørgrav if (ci->address == NULL)
116847dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("Address", "addr");
1169462c32cbSDag-Erling Smørgrav switch (addr_match_list(ci->address, arg)) {
1170d4af9e69SDag-Erling Smørgrav case 1:
1171333ee039SDag-Erling Smørgrav debug("connection from %.100s matched 'Address "
1172462c32cbSDag-Erling Smørgrav "%.100s' at line %d", ci->address, arg, line);
1173d4af9e69SDag-Erling Smørgrav break;
1174d4af9e69SDag-Erling Smørgrav case 0:
1175d4af9e69SDag-Erling Smørgrav case -1:
1176d4af9e69SDag-Erling Smørgrav result = 0;
1177d4af9e69SDag-Erling Smørgrav break;
1178d4af9e69SDag-Erling Smørgrav case -2:
1179*0ae642c7SEd Maste result = -1;
1180*0ae642c7SEd Maste goto out;
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:
1205*0ae642c7SEd Maste result = -1;
1206*0ae642c7SEd Maste goto out;
1207462c32cbSDag-Erling Smørgrav }
1208462c32cbSDag-Erling Smørgrav } else if (strcasecmp(attrib, "localport") == 0) {
1209462c32cbSDag-Erling Smørgrav if ((port = a2port(arg)) == -1) {
1210462c32cbSDag-Erling Smørgrav error("Invalid LocalPort '%s' on Match line",
1211462c32cbSDag-Erling Smørgrav arg);
1212*0ae642c7SEd Maste result = -1;
1213*0ae642c7SEd Maste goto out;
1214462c32cbSDag-Erling Smørgrav }
121519261079SEd Maste if (ci == NULL || (ci->test && ci->lport == -1)) {
1216462c32cbSDag-Erling Smørgrav result = 0;
1217462c32cbSDag-Erling Smørgrav continue;
1218462c32cbSDag-Erling Smørgrav }
121947dd1d1bSDag-Erling Smørgrav if (ci->lport == 0)
122047dd1d1bSDag-Erling Smørgrav match_test_missing_fatal("LocalPort", "lport");
1221462c32cbSDag-Erling Smørgrav /* TODO support port lists */
1222462c32cbSDag-Erling Smørgrav if (port == ci->lport)
1223462c32cbSDag-Erling Smørgrav debug("connection from %.100s matched "
1224462c32cbSDag-Erling Smørgrav "'LocalPort %d' at line %d",
1225462c32cbSDag-Erling Smørgrav ci->laddress, port, line);
1226462c32cbSDag-Erling Smørgrav else
1227462c32cbSDag-Erling Smørgrav result = 0;
122847dd1d1bSDag-Erling Smørgrav } else if (strcasecmp(attrib, "rdomain") == 0) {
122919261079SEd Maste if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
123047dd1d1bSDag-Erling Smørgrav result = 0;
123147dd1d1bSDag-Erling Smørgrav continue;
123247dd1d1bSDag-Erling Smørgrav }
123319261079SEd Maste if (ci->rdomain == NULL)
123419261079SEd Maste match_test_missing_fatal("RDomain", "rdomain");
123547dd1d1bSDag-Erling Smørgrav if (match_pattern_list(ci->rdomain, arg, 0) != 1)
123647dd1d1bSDag-Erling Smørgrav result = 0;
123747dd1d1bSDag-Erling Smørgrav else
123847dd1d1bSDag-Erling Smørgrav debug("user %.100s matched 'RDomain %.100s' at "
123947dd1d1bSDag-Erling Smørgrav "line %d", ci->rdomain, arg, line);
1240333ee039SDag-Erling Smørgrav } else {
1241*0ae642c7SEd Maste error("Unsupported Match attribute %s", oattrib);
1242*0ae642c7SEd Maste result = -1;
1243*0ae642c7SEd Maste goto out;
1244333ee039SDag-Erling Smørgrav }
1245*0ae642c7SEd Maste free(attrib);
1246*0ae642c7SEd Maste attrib = NULL;
1247333ee039SDag-Erling Smørgrav }
1248f7167e0eSDag-Erling Smørgrav if (attributes == 0) {
1249f7167e0eSDag-Erling Smørgrav error("One or more attributes required for Match");
1250f7167e0eSDag-Erling Smørgrav return -1;
1251f7167e0eSDag-Erling Smørgrav }
1252*0ae642c7SEd Maste out:
1253*0ae642c7SEd Maste if (ci != NULL && result != -1)
1254333ee039SDag-Erling Smørgrav debug3("match %sfound", result ? "" : "not ");
1255*0ae642c7SEd Maste free(attrib);
1256333ee039SDag-Erling Smørgrav return result;
1257333ee039SDag-Erling Smørgrav }
1258333ee039SDag-Erling Smørgrav
1259333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1260333ee039SDag-Erling Smørgrav
1261e146993eSDag-Erling Smørgrav /* Multistate option parsing */
1262e146993eSDag-Erling Smørgrav struct multistate {
1263e146993eSDag-Erling Smørgrav char *key;
1264e146993eSDag-Erling Smørgrav int value;
1265e146993eSDag-Erling Smørgrav };
126647dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
126747dd1d1bSDag-Erling Smørgrav { "yes", 1 },
126847dd1d1bSDag-Erling Smørgrav { "no", 0 },
126947dd1d1bSDag-Erling Smørgrav { NULL, -1 }
127047dd1d1bSDag-Erling Smørgrav };
127119261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = {
127219261079SEd Maste { "yes", IGNORE_RHOSTS_YES },
127319261079SEd Maste { "no", IGNORE_RHOSTS_NO },
127419261079SEd Maste { "shosts-only", IGNORE_RHOSTS_SHOSTS },
127519261079SEd Maste { NULL, -1 }
127619261079SEd Maste };
1277e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
1278e146993eSDag-Erling Smørgrav { "inet", AF_INET },
1279e146993eSDag-Erling Smørgrav { "inet6", AF_INET6 },
1280e146993eSDag-Erling Smørgrav { "any", AF_UNSPEC },
1281e146993eSDag-Erling Smørgrav { NULL, -1 }
1282e146993eSDag-Erling Smørgrav };
1283e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = {
1284e146993eSDag-Erling Smørgrav { "without-password", PERMIT_NO_PASSWD },
1285eccfee6eSDag-Erling Smørgrav { "prohibit-password", PERMIT_NO_PASSWD },
1286e146993eSDag-Erling Smørgrav { "forced-commands-only", PERMIT_FORCED_ONLY },
1287e146993eSDag-Erling Smørgrav { "yes", PERMIT_YES },
1288e146993eSDag-Erling Smørgrav { "no", PERMIT_NO },
1289e146993eSDag-Erling Smørgrav { NULL, -1 }
1290e146993eSDag-Erling Smørgrav };
1291e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = {
129219261079SEd Maste #ifdef WITH_ZLIB
1293ca86bcf2SDag-Erling Smørgrav { "yes", COMP_DELAYED },
1294e146993eSDag-Erling Smørgrav { "delayed", COMP_DELAYED },
129519261079SEd Maste #endif
1296e146993eSDag-Erling Smørgrav { "no", COMP_NONE },
1297e146993eSDag-Erling Smørgrav { NULL, -1 }
1298e146993eSDag-Erling Smørgrav };
1299e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = {
1300e146993eSDag-Erling Smørgrav { "clientspecified", 2 },
1301e146993eSDag-Erling Smørgrav { "yes", 1 },
1302e146993eSDag-Erling Smørgrav { "no", 0 },
1303e146993eSDag-Erling Smørgrav { NULL, -1 }
1304e146993eSDag-Erling Smørgrav };
13056888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = {
13066888a9beSDag-Erling Smørgrav { "yes", FORWARD_ALLOW },
13076888a9beSDag-Erling Smørgrav { "all", FORWARD_ALLOW },
13086888a9beSDag-Erling Smørgrav { "no", FORWARD_DENY },
13096888a9beSDag-Erling Smørgrav { "remote", FORWARD_REMOTE },
13106888a9beSDag-Erling Smørgrav { "local", FORWARD_LOCAL },
13116888a9beSDag-Erling Smørgrav { NULL, -1 }
13126888a9beSDag-Erling Smørgrav };
1313e146993eSDag-Erling Smørgrav
131419261079SEd Maste static int
process_server_config_line_depth(ServerOptions * options,char * line,const char * filename,int linenum,int * activep,struct connection_info * connectinfo,int * inc_flags,int depth,struct include_list * includes)131519261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line,
1316462c32cbSDag-Erling Smørgrav const char *filename, int linenum, int *activep,
131719261079SEd Maste struct connection_info *connectinfo, int *inc_flags, int depth,
131819261079SEd Maste struct include_list *includes)
1319511b41d2SMark Murray {
13201323ec57SEd Maste char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
1321a91a2465SEd Maste int cmdline = 0, *intptr, value, value2, n, port, oactive, r;
1322a91a2465SEd Maste int ca_only = 0, found = 0;
1323d4af9e69SDag-Erling Smørgrav SyslogFacility *log_facility_ptr;
1324d4af9e69SDag-Erling Smørgrav LogLevel *log_level_ptr;
1325511b41d2SMark Murray ServerOpCodes opcode;
1326a91a2465SEd Maste u_int i, *uintptr, flags = 0;
1327333ee039SDag-Erling Smørgrav size_t len;
1328e4a9863fSDag-Erling Smørgrav long long val64;
1329e146993eSDag-Erling Smørgrav const struct multistate *multistate_ptr;
133047dd1d1bSDag-Erling Smørgrav const char *errstr;
133119261079SEd Maste struct include_item *item;
133219261079SEd Maste glob_t gbuf;
133319261079SEd Maste char **oav = NULL, **av;
133419261079SEd Maste int oac = 0, ac;
133519261079SEd Maste int ret = -1;
1336a91a2465SEd Maste char **strs = NULL; /* string array arguments; freed implicitly */
1337a91a2465SEd Maste u_int nstrs = 0;
1338511b41d2SMark Murray
1339d93a896eSDag-Erling Smørgrav /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1340d93a896eSDag-Erling Smørgrav if ((len = strlen(line)) == 0)
1341d93a896eSDag-Erling Smørgrav return 0;
1342d93a896eSDag-Erling Smørgrav for (len--; len > 0; len--) {
1343d93a896eSDag-Erling Smørgrav if (strchr(WHITESPACE "\f", line[len]) == NULL)
1344d93a896eSDag-Erling Smørgrav break;
1345d93a896eSDag-Erling Smørgrav line[len] = '\0';
1346d93a896eSDag-Erling Smørgrav }
1347d93a896eSDag-Erling Smørgrav
134819261079SEd Maste str = line;
134919261079SEd Maste if ((keyword = strdelim(&str)) == NULL)
1350333ee039SDag-Erling Smørgrav return 0;
1351c2d3a559SKris Kennaway /* Ignore leading whitespace */
135219261079SEd Maste if (*keyword == '\0')
135319261079SEd Maste keyword = strdelim(&str);
135419261079SEd Maste if (!keyword || !*keyword || *keyword == '#')
1355af12a3e7SDag-Erling Smørgrav return 0;
135619261079SEd Maste if (str == NULL || *str == '\0') {
135719261079SEd Maste error("%s line %d: no argument after keyword \"%s\"",
135819261079SEd Maste filename, linenum, keyword);
135919261079SEd Maste return -1;
136019261079SEd Maste }
1361ca3176e7SBrian Feldman intptr = NULL;
1362ca3176e7SBrian Feldman charptr = NULL;
136319261079SEd Maste opcode = parse_token(keyword, filename, linenum, &flags);
136419261079SEd Maste
136519261079SEd Maste if (argv_split(str, &oac, &oav, 1) != 0) {
136619261079SEd Maste error("%s line %d: invalid quotes", filename, linenum);
136719261079SEd Maste return -1;
136819261079SEd Maste }
136919261079SEd Maste ac = oac;
137019261079SEd Maste av = oav;
1371333ee039SDag-Erling Smørgrav
1372333ee039SDag-Erling Smørgrav if (activep == NULL) { /* We are processing a command line directive */
1373333ee039SDag-Erling Smørgrav cmdline = 1;
1374333ee039SDag-Erling Smørgrav activep = &cmdline;
1375333ee039SDag-Erling Smørgrav }
137619261079SEd Maste if (*activep && opcode != sMatch && opcode != sInclude)
137719261079SEd Maste debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1378333ee039SDag-Erling Smørgrav if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1379462c32cbSDag-Erling Smørgrav if (connectinfo == NULL) {
1380333ee039SDag-Erling Smørgrav fatal("%s line %d: Directive '%s' is not allowed "
138119261079SEd Maste "within a Match block", filename, linenum, keyword);
1382333ee039SDag-Erling Smørgrav } else { /* this is a directive we have already processed */
138319261079SEd Maste ret = 0;
138419261079SEd Maste goto out;
1385333ee039SDag-Erling Smørgrav }
1386333ee039SDag-Erling Smørgrav }
1387333ee039SDag-Erling Smørgrav
1388511b41d2SMark Murray switch (opcode) {
1389989dd127SDag-Erling Smørgrav /* Portable-specific options */
1390cf2b5f3bSDag-Erling Smørgrav case sUsePAM:
1391cf2b5f3bSDag-Erling Smørgrav intptr = &options->use_pam;
1392989dd127SDag-Erling Smørgrav goto parse_flag;
13930fdf8faeSEd Maste case sPAMServiceName:
13940fdf8faeSEd Maste charptr = &options->pam_service_name;
13950fdf8faeSEd Maste arg = argv_next(&ac, &av);
13960fdf8faeSEd Maste if (!arg || *arg == '\0') {
13970fdf8faeSEd Maste fatal("%s line %d: missing argument.",
13980fdf8faeSEd Maste filename, linenum);
13990fdf8faeSEd Maste }
14000fdf8faeSEd Maste if (*activep && *charptr == NULL)
14010fdf8faeSEd Maste *charptr = xstrdup(arg);
14020fdf8faeSEd Maste break;
1403989dd127SDag-Erling Smørgrav
1404989dd127SDag-Erling Smørgrav /* Standard Options */
1405511b41d2SMark Murray case sBadOption:
140619261079SEd Maste goto out;
1407511b41d2SMark Murray case sPort:
1408511b41d2SMark Murray /* ignore ports from configfile if cmdline specifies ports */
140919261079SEd Maste if (options->ports_from_cmdline) {
141019261079SEd Maste argv_consume(&ac);
141119261079SEd Maste break;
141219261079SEd Maste }
1413511b41d2SMark Murray if (options->num_ports >= MAX_PORTS)
1414ca3176e7SBrian Feldman fatal("%s line %d: too many ports.",
1415511b41d2SMark Murray filename, linenum);
141619261079SEd Maste arg = argv_next(&ac, &av);
1417c2d3a559SKris Kennaway if (!arg || *arg == '\0')
1418ca3176e7SBrian Feldman fatal("%s line %d: missing port number.",
1419511b41d2SMark Murray filename, linenum);
1420ca3176e7SBrian Feldman options->ports[options->num_ports++] = a2port(arg);
1421cce7d346SDag-Erling Smørgrav if (options->ports[options->num_ports-1] <= 0)
1422ca3176e7SBrian Feldman fatal("%s line %d: Badly formatted port number.",
1423ca3176e7SBrian Feldman filename, linenum);
1424511b41d2SMark Murray break;
1425511b41d2SMark Murray
1426511b41d2SMark Murray case sLoginGraceTime:
1427511b41d2SMark Murray intptr = &options->login_grace_time;
1428af12a3e7SDag-Erling Smørgrav parse_time:
142919261079SEd Maste arg = argv_next(&ac, &av);
1430af12a3e7SDag-Erling Smørgrav if (!arg || *arg == '\0')
1431af12a3e7SDag-Erling Smørgrav fatal("%s line %d: missing time value.",
1432af12a3e7SDag-Erling Smørgrav filename, linenum);
1433af12a3e7SDag-Erling Smørgrav if ((value = convtime(arg)) == -1)
1434af12a3e7SDag-Erling Smørgrav fatal("%s line %d: invalid time value.",
1435af12a3e7SDag-Erling Smørgrav filename, linenum);
1436557f75e5SDag-Erling Smørgrav if (*activep && *intptr == -1)
1437af12a3e7SDag-Erling Smørgrav *intptr = value;
1438af12a3e7SDag-Erling Smørgrav break;
1439511b41d2SMark Murray
1440511b41d2SMark Murray case sListenAddress:
144119261079SEd Maste arg = argv_next(&ac, &av);
1442aa49c926SDag-Erling Smørgrav if (arg == NULL || *arg == '\0')
1443aa49c926SDag-Erling Smørgrav fatal("%s line %d: missing address",
1444511b41d2SMark Murray filename, linenum);
1445d4ecd108SDag-Erling Smørgrav /* check for bare IPv6 address: no "[]" and 2 or more ":" */
1446d4ecd108SDag-Erling Smørgrav if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1447d4ecd108SDag-Erling Smørgrav && strchr(p+1, ':') != NULL) {
144847dd1d1bSDag-Erling Smørgrav port = 0;
144947dd1d1bSDag-Erling Smørgrav p = arg;
145047dd1d1bSDag-Erling Smørgrav } else {
145119261079SEd Maste arg2 = NULL;
14521323ec57SEd Maste p = hpdelim(&arg);
14531323ec57SEd Maste if (p == NULL)
1454aa49c926SDag-Erling Smørgrav fatal("%s line %d: bad address:port usage",
1455ca3176e7SBrian Feldman filename, linenum);
1456aa49c926SDag-Erling Smørgrav p = cleanhostname(p);
1457aa49c926SDag-Erling Smørgrav if (arg == NULL)
1458aa49c926SDag-Erling Smørgrav port = 0;
1459cce7d346SDag-Erling Smørgrav else if ((port = a2port(arg)) <= 0)
146047dd1d1bSDag-Erling Smørgrav fatal("%s line %d: bad port number",
146147dd1d1bSDag-Erling Smørgrav filename, linenum);
146247dd1d1bSDag-Erling Smørgrav }
146347dd1d1bSDag-Erling Smørgrav /* Optional routing table */
146447dd1d1bSDag-Erling Smørgrav arg2 = NULL;
146519261079SEd Maste if ((arg = argv_next(&ac, &av)) != NULL) {
146647dd1d1bSDag-Erling Smørgrav if (strcmp(arg, "rdomain") != 0 ||
146719261079SEd Maste (arg2 = argv_next(&ac, &av)) == NULL)
146847dd1d1bSDag-Erling Smørgrav fatal("%s line %d: bad ListenAddress syntax",
146947dd1d1bSDag-Erling Smørgrav filename, linenum);
147047dd1d1bSDag-Erling Smørgrav if (!valid_rdomain(arg2))
147147dd1d1bSDag-Erling Smørgrav fatal("%s line %d: bad routing domain",
147247dd1d1bSDag-Erling Smørgrav filename, linenum);
147347dd1d1bSDag-Erling Smørgrav }
147447dd1d1bSDag-Erling Smørgrav queue_listen_addr(options, p, arg2, port);
1475aa49c926SDag-Erling Smørgrav
1476aa49c926SDag-Erling Smørgrav break;
1477aa49c926SDag-Erling Smørgrav
1478aa49c926SDag-Erling Smørgrav case sAddressFamily:
1479e146993eSDag-Erling Smørgrav intptr = &options->address_family;
1480e146993eSDag-Erling Smørgrav multistate_ptr = multistate_addressfamily;
1481e146993eSDag-Erling Smørgrav parse_multistate:
148219261079SEd Maste arg = argv_next(&ac, &av);
1483d4ecd108SDag-Erling Smørgrav if (!arg || *arg == '\0')
1484e146993eSDag-Erling Smørgrav fatal("%s line %d: missing argument.",
1485d4ecd108SDag-Erling Smørgrav filename, linenum);
1486e146993eSDag-Erling Smørgrav value = -1;
1487e146993eSDag-Erling Smørgrav for (i = 0; multistate_ptr[i].key != NULL; i++) {
1488e146993eSDag-Erling Smørgrav if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1489e146993eSDag-Erling Smørgrav value = multistate_ptr[i].value;
1490e146993eSDag-Erling Smørgrav break;
1491e146993eSDag-Erling Smørgrav }
1492e146993eSDag-Erling Smørgrav }
1493e146993eSDag-Erling Smørgrav if (value == -1)
1494e146993eSDag-Erling Smørgrav fatal("%s line %d: unsupported option \"%s\".",
1495aa49c926SDag-Erling Smørgrav filename, linenum, arg);
1496e146993eSDag-Erling Smørgrav if (*activep && *intptr == -1)
1497aa49c926SDag-Erling Smørgrav *intptr = value;
1498511b41d2SMark Murray break;
1499511b41d2SMark Murray
1500511b41d2SMark Murray case sHostKeyFile:
150119261079SEd Maste arg = argv_next(&ac, &av);
1502ca3176e7SBrian Feldman if (!arg || *arg == '\0')
1503ca3176e7SBrian Feldman fatal("%s line %d: missing file name.",
1504e8aafc91SKris Kennaway filename, linenum);
150519261079SEd Maste if (*activep) {
150619261079SEd Maste servconf_add_hostkey(filename, linenum,
150719261079SEd Maste options, arg, 1);
150819261079SEd Maste }
1509e8aafc91SKris Kennaway break;
1510e8aafc91SKris Kennaway
1511e4a9863fSDag-Erling Smørgrav case sHostKeyAgent:
1512e4a9863fSDag-Erling Smørgrav charptr = &options->host_key_agent;
151319261079SEd Maste arg = argv_next(&ac, &av);
1514e4a9863fSDag-Erling Smørgrav if (!arg || *arg == '\0')
1515e4a9863fSDag-Erling Smørgrav fatal("%s line %d: missing socket name.",
1516e4a9863fSDag-Erling Smørgrav filename, linenum);
1517e4a9863fSDag-Erling Smørgrav if (*activep && *charptr == NULL)
1518e4a9863fSDag-Erling Smørgrav *charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1519e4a9863fSDag-Erling Smørgrav xstrdup(arg) : derelativise_path(arg);
1520e4a9863fSDag-Erling Smørgrav break;
1521e4a9863fSDag-Erling Smørgrav
1522b15c8340SDag-Erling Smørgrav case sHostCertificate:
152319261079SEd Maste arg = argv_next(&ac, &av);
152447dd1d1bSDag-Erling Smørgrav if (!arg || *arg == '\0')
152547dd1d1bSDag-Erling Smørgrav fatal("%s line %d: missing file name.",
152647dd1d1bSDag-Erling Smørgrav filename, linenum);
152747dd1d1bSDag-Erling Smørgrav if (*activep)
152847dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(filename, linenum, options, arg);
152947dd1d1bSDag-Erling Smørgrav break;
1530b15c8340SDag-Erling Smørgrav
1531e8aafc91SKris Kennaway case sPidFile:
1532e8aafc91SKris Kennaway charptr = &options->pid_file;
153347dd1d1bSDag-Erling Smørgrav parse_filename:
153419261079SEd Maste arg = argv_next(&ac, &av);
153547dd1d1bSDag-Erling Smørgrav if (!arg || *arg == '\0')
153647dd1d1bSDag-Erling Smørgrav fatal("%s line %d: missing file name.",
153747dd1d1bSDag-Erling Smørgrav filename, linenum);
153847dd1d1bSDag-Erling Smørgrav if (*activep && *charptr == NULL) {
153947dd1d1bSDag-Erling Smørgrav *charptr = derelativise_path(arg);
154047dd1d1bSDag-Erling Smørgrav /* increase optional counter */
154147dd1d1bSDag-Erling Smørgrav if (intptr != NULL)
154247dd1d1bSDag-Erling Smørgrav *intptr = *intptr + 1;
154347dd1d1bSDag-Erling Smørgrav }
154447dd1d1bSDag-Erling Smørgrav break;
1545511b41d2SMark Murray
154619261079SEd Maste case sModuliFile:
154719261079SEd Maste charptr = &options->moduli_file;
154819261079SEd Maste goto parse_filename;
154919261079SEd Maste
1550511b41d2SMark Murray case sPermitRootLogin:
1551511b41d2SMark Murray intptr = &options->permit_root_login;
1552e146993eSDag-Erling Smørgrav multistate_ptr = multistate_permitrootlogin;
1553e146993eSDag-Erling Smørgrav goto parse_multistate;
1554511b41d2SMark Murray
1555511b41d2SMark Murray case sIgnoreRhosts:
1556511b41d2SMark Murray intptr = &options->ignore_rhosts;
155719261079SEd Maste multistate_ptr = multistate_ignore_rhosts;
155847dd1d1bSDag-Erling Smørgrav goto parse_multistate;
1559511b41d2SMark Murray
1560511b41d2SMark Murray case sIgnoreUserKnownHosts:
1561511b41d2SMark Murray intptr = &options->ignore_user_known_hosts;
156219261079SEd Maste parse_flag:
156319261079SEd Maste multistate_ptr = multistate_flag;
156419261079SEd Maste goto parse_multistate;
1565511b41d2SMark Murray
1566ca3176e7SBrian Feldman case sHostbasedAuthentication:
1567ca3176e7SBrian Feldman intptr = &options->hostbased_authentication;
1568ca3176e7SBrian Feldman goto parse_flag;
1569ca3176e7SBrian Feldman
1570ca3176e7SBrian Feldman case sHostbasedUsesNameFromPacketOnly:
1571ca3176e7SBrian Feldman intptr = &options->hostbased_uses_name_from_packet_only;
1572ca3176e7SBrian Feldman goto parse_flag;
1573ca3176e7SBrian Feldman
157419261079SEd Maste case sHostbasedAcceptedAlgorithms:
157519261079SEd Maste charptr = &options->hostbased_accepted_algos;
1576535af610SEd Maste ca_only = 0;
157719261079SEd Maste parse_pubkey_algos:
157819261079SEd Maste arg = argv_next(&ac, &av);
1579bc5531deSDag-Erling Smørgrav if (!arg || *arg == '\0')
1580bc5531deSDag-Erling Smørgrav fatal("%s line %d: Missing argument.",
1581bc5531deSDag-Erling Smørgrav filename, linenum);
1582d93a896eSDag-Erling Smørgrav if (*arg != '-' &&
158319261079SEd Maste !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1584535af610SEd Maste arg + 1 : arg, 1, ca_only))
1585bc5531deSDag-Erling Smørgrav fatal("%s line %d: Bad key types '%s'.",
1586bc5531deSDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>");
1587bc5531deSDag-Erling Smørgrav if (*activep && *charptr == NULL)
1588bc5531deSDag-Erling Smørgrav *charptr = xstrdup(arg);
1589bc5531deSDag-Erling Smørgrav break;
1590bc5531deSDag-Erling Smørgrav
1591eccfee6eSDag-Erling Smørgrav case sHostKeyAlgorithms:
1592eccfee6eSDag-Erling Smørgrav charptr = &options->hostkeyalgorithms;
1593535af610SEd Maste ca_only = 0;
159419261079SEd Maste goto parse_pubkey_algos;
1595eccfee6eSDag-Erling Smørgrav
15962f513db7SEd Maste case sCASignatureAlgorithms:
15972f513db7SEd Maste charptr = &options->ca_sign_algorithms;
1598535af610SEd Maste ca_only = 1;
159919261079SEd Maste goto parse_pubkey_algos;
16002f513db7SEd Maste
1601ca3176e7SBrian Feldman case sPubkeyAuthentication:
1602ca3176e7SBrian Feldman intptr = &options->pubkey_authentication;
1603535af610SEd Maste ca_only = 0;
1604e8aafc91SKris Kennaway goto parse_flag;
1605cf2b5f3bSDag-Erling Smørgrav
160619261079SEd Maste case sPubkeyAcceptedAlgorithms:
160719261079SEd Maste charptr = &options->pubkey_accepted_algos;
1608535af610SEd Maste ca_only = 0;
160919261079SEd Maste goto parse_pubkey_algos;
161019261079SEd Maste
161119261079SEd Maste case sPubkeyAuthOptions:
161219261079SEd Maste intptr = &options->pubkey_auth_options;
161319261079SEd Maste value = 0;
161419261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
161519261079SEd Maste if (strcasecmp(arg, "none") == 0)
161619261079SEd Maste continue;
161719261079SEd Maste if (strcasecmp(arg, "touch-required") == 0)
161819261079SEd Maste value |= PUBKEYAUTH_TOUCH_REQUIRED;
161919261079SEd Maste else if (strcasecmp(arg, "verify-required") == 0)
162019261079SEd Maste value |= PUBKEYAUTH_VERIFY_REQUIRED;
162119261079SEd Maste else {
162219261079SEd Maste error("%s line %d: unsupported %s option %s",
162319261079SEd Maste filename, linenum, keyword, arg);
162419261079SEd Maste goto out;
162519261079SEd Maste }
162619261079SEd Maste }
162719261079SEd Maste if (*activep && *intptr == -1)
162819261079SEd Maste *intptr = value;
162919261079SEd Maste break;
1630bc5531deSDag-Erling Smørgrav
1631cb96ab36SAssar Westerlund case sKerberosAuthentication:
1632cb96ab36SAssar Westerlund intptr = &options->kerberos_authentication;
1633511b41d2SMark Murray goto parse_flag;
1634511b41d2SMark Murray
1635af12a3e7SDag-Erling Smørgrav case sKerberosOrLocalPasswd:
1636af12a3e7SDag-Erling Smørgrav intptr = &options->kerberos_or_local_passwd;
1637511b41d2SMark Murray goto parse_flag;
1638511b41d2SMark Murray
1639af12a3e7SDag-Erling Smørgrav case sKerberosTicketCleanup:
1640af12a3e7SDag-Erling Smørgrav intptr = &options->kerberos_ticket_cleanup;
1641511b41d2SMark Murray goto parse_flag;
1642cf2b5f3bSDag-Erling Smørgrav
16431ec0d754SDag-Erling Smørgrav case sKerberosGetAFSToken:
16441ec0d754SDag-Erling Smørgrav intptr = &options->kerberos_get_afs_token;
16451ec0d754SDag-Erling Smørgrav goto parse_flag;
16461ec0d754SDag-Erling Smørgrav
1647cf2b5f3bSDag-Erling Smørgrav case sGssAuthentication:
1648cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_authentication;
1649fe5fd017SMark Murray goto parse_flag;
1650cf2b5f3bSDag-Erling Smørgrav
1651cf2b5f3bSDag-Erling Smørgrav case sGssCleanupCreds:
1652cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_cleanup_creds;
1653511b41d2SMark Murray goto parse_flag;
1654511b41d2SMark Murray
1655557f75e5SDag-Erling Smørgrav case sGssStrictAcceptor:
1656557f75e5SDag-Erling Smørgrav intptr = &options->gss_strict_acceptor;
1657557f75e5SDag-Erling Smørgrav goto parse_flag;
1658557f75e5SDag-Erling Smørgrav
1659511b41d2SMark Murray case sPasswordAuthentication:
1660511b41d2SMark Murray intptr = &options->password_authentication;
1661511b41d2SMark Murray goto parse_flag;
1662511b41d2SMark Murray
166309958426SBrian Feldman case sKbdInteractiveAuthentication:
166409958426SBrian Feldman intptr = &options->kbd_interactive_authentication;
166509958426SBrian Feldman goto parse_flag;
166609958426SBrian Feldman
1667511b41d2SMark Murray case sPrintMotd:
1668511b41d2SMark Murray intptr = &options->print_motd;
1669511b41d2SMark Murray goto parse_flag;
1670511b41d2SMark Murray
1671ca3176e7SBrian Feldman case sPrintLastLog:
1672ca3176e7SBrian Feldman intptr = &options->print_lastlog;
1673ca3176e7SBrian Feldman goto parse_flag;
1674ca3176e7SBrian Feldman
1675511b41d2SMark Murray case sX11Forwarding:
1676511b41d2SMark Murray intptr = &options->x11_forwarding;
1677511b41d2SMark Murray goto parse_flag;
1678511b41d2SMark Murray
1679511b41d2SMark Murray case sX11DisplayOffset:
1680511b41d2SMark Murray intptr = &options->x11_display_offset;
1681ca86bcf2SDag-Erling Smørgrav parse_int:
168219261079SEd Maste arg = argv_next(&ac, &av);
168347dd1d1bSDag-Erling Smørgrav if ((errstr = atoi_err(arg, &value)) != NULL)
168419261079SEd Maste fatal("%s line %d: %s integer value %s.",
168519261079SEd Maste filename, linenum, keyword, errstr);
1686ca86bcf2SDag-Erling Smørgrav if (*activep && *intptr == -1)
1687ca86bcf2SDag-Erling Smørgrav *intptr = value;
1688ca86bcf2SDag-Erling Smørgrav break;
1689511b41d2SMark Murray
1690af12a3e7SDag-Erling Smørgrav case sX11UseLocalhost:
1691af12a3e7SDag-Erling Smørgrav intptr = &options->x11_use_localhost;
1692af12a3e7SDag-Erling Smørgrav goto parse_flag;
1693af12a3e7SDag-Erling Smørgrav
1694c2d3a559SKris Kennaway case sXAuthLocation:
1695c2d3a559SKris Kennaway charptr = &options->xauth_location;
1696c2d3a559SKris Kennaway goto parse_filename;
1697c2d3a559SKris Kennaway
1698f7167e0eSDag-Erling Smørgrav case sPermitTTY:
1699f7167e0eSDag-Erling Smørgrav intptr = &options->permit_tty;
1700f7167e0eSDag-Erling Smørgrav goto parse_flag;
1701f7167e0eSDag-Erling Smørgrav
1702a0ee8cc6SDag-Erling Smørgrav case sPermitUserRC:
1703a0ee8cc6SDag-Erling Smørgrav intptr = &options->permit_user_rc;
1704a0ee8cc6SDag-Erling Smørgrav goto parse_flag;
1705a0ee8cc6SDag-Erling Smørgrav
1706511b41d2SMark Murray case sStrictModes:
1707511b41d2SMark Murray intptr = &options->strict_modes;
1708511b41d2SMark Murray goto parse_flag;
1709511b41d2SMark Murray
17101ec0d754SDag-Erling Smørgrav case sTCPKeepAlive:
17111ec0d754SDag-Erling Smørgrav intptr = &options->tcp_keep_alive;
1712511b41d2SMark Murray goto parse_flag;
1713511b41d2SMark Murray
1714511b41d2SMark Murray case sEmptyPasswd:
1715511b41d2SMark Murray intptr = &options->permit_empty_passwd;
1716511b41d2SMark Murray goto parse_flag;
1717511b41d2SMark Murray
1718f388f5efSDag-Erling Smørgrav case sPermitUserEnvironment:
1719f388f5efSDag-Erling Smørgrav intptr = &options->permit_user_env;
172019261079SEd Maste charptr = &options->permit_user_env_allowlist;
172119261079SEd Maste arg = argv_next(&ac, &av);
1722190cef3dSDag-Erling Smørgrav if (!arg || *arg == '\0')
172319261079SEd Maste fatal("%s line %d: %s missing argument.",
172419261079SEd Maste filename, linenum, keyword);
1725190cef3dSDag-Erling Smørgrav value = 0;
1726190cef3dSDag-Erling Smørgrav p = NULL;
1727190cef3dSDag-Erling Smørgrav if (strcmp(arg, "yes") == 0)
1728190cef3dSDag-Erling Smørgrav value = 1;
1729190cef3dSDag-Erling Smørgrav else if (strcmp(arg, "no") == 0)
1730190cef3dSDag-Erling Smørgrav value = 0;
1731190cef3dSDag-Erling Smørgrav else {
1732190cef3dSDag-Erling Smørgrav /* Pattern-list specified */
1733190cef3dSDag-Erling Smørgrav value = 1;
1734190cef3dSDag-Erling Smørgrav p = xstrdup(arg);
1735190cef3dSDag-Erling Smørgrav }
1736190cef3dSDag-Erling Smørgrav if (*activep && *intptr == -1) {
1737190cef3dSDag-Erling Smørgrav *intptr = value;
1738190cef3dSDag-Erling Smørgrav *charptr = p;
1739190cef3dSDag-Erling Smørgrav p = NULL;
1740190cef3dSDag-Erling Smørgrav }
1741190cef3dSDag-Erling Smørgrav free(p);
1742190cef3dSDag-Erling Smørgrav break;
1743f388f5efSDag-Erling Smørgrav
174480628bacSDag-Erling Smørgrav case sCompression:
174580628bacSDag-Erling Smørgrav intptr = &options->compression;
1746e146993eSDag-Erling Smørgrav multistate_ptr = multistate_compression;
1747e146993eSDag-Erling Smørgrav goto parse_multistate;
174880628bacSDag-Erling Smørgrav
1749e4a9863fSDag-Erling Smørgrav case sRekeyLimit:
175019261079SEd Maste arg = argv_next(&ac, &av);
1751e4a9863fSDag-Erling Smørgrav if (!arg || *arg == '\0')
175219261079SEd Maste fatal("%s line %d: %s missing argument.",
175319261079SEd Maste filename, linenum, keyword);
1754e4a9863fSDag-Erling Smørgrav if (strcmp(arg, "default") == 0) {
1755e4a9863fSDag-Erling Smørgrav val64 = 0;
1756e4a9863fSDag-Erling Smørgrav } else {
1757e4a9863fSDag-Erling Smørgrav if (scan_scaled(arg, &val64) == -1)
175819261079SEd Maste fatal("%.200s line %d: Bad %s number '%s': %s",
175919261079SEd Maste filename, linenum, keyword,
176019261079SEd Maste arg, strerror(errno));
1761e4a9863fSDag-Erling Smørgrav if (val64 != 0 && val64 < 16)
176219261079SEd Maste fatal("%.200s line %d: %s too small",
176319261079SEd Maste filename, linenum, keyword);
1764e4a9863fSDag-Erling Smørgrav }
1765e4a9863fSDag-Erling Smørgrav if (*activep && options->rekey_limit == -1)
1766acc1a9efSDag-Erling Smørgrav options->rekey_limit = val64;
176719261079SEd Maste if (ac != 0) { /* optional rekey interval present */
176819261079SEd Maste if (strcmp(av[0], "none") == 0) {
176919261079SEd Maste (void)argv_next(&ac, &av); /* discard */
1770e4a9863fSDag-Erling Smørgrav break;
1771e4a9863fSDag-Erling Smørgrav }
1772e4a9863fSDag-Erling Smørgrav intptr = &options->rekey_interval;
1773e4a9863fSDag-Erling Smørgrav goto parse_time;
1774e4a9863fSDag-Erling Smørgrav }
1775e4a9863fSDag-Erling Smørgrav break;
1776e4a9863fSDag-Erling Smørgrav
1777e8aafc91SKris Kennaway case sGatewayPorts:
1778a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.gateway_ports;
1779e146993eSDag-Erling Smørgrav multistate_ptr = multistate_gatewayports;
1780e146993eSDag-Erling Smørgrav goto parse_multistate;
1781e8aafc91SKris Kennaway
1782cf2b5f3bSDag-Erling Smørgrav case sUseDNS:
1783cf2b5f3bSDag-Erling Smørgrav intptr = &options->use_dns;
1784ca3176e7SBrian Feldman goto parse_flag;
1785ca3176e7SBrian Feldman
1786511b41d2SMark Murray case sLogFacility:
1787d4af9e69SDag-Erling Smørgrav log_facility_ptr = &options->log_facility;
178819261079SEd Maste arg = argv_next(&ac, &av);
1789c2d3a559SKris Kennaway value = log_facility_number(arg);
1790af12a3e7SDag-Erling Smørgrav if (value == SYSLOG_FACILITY_NOT_SET)
1791ca3176e7SBrian Feldman fatal("%.200s line %d: unsupported log facility '%s'",
1792c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>");
1793d4af9e69SDag-Erling Smørgrav if (*log_facility_ptr == -1)
1794d4af9e69SDag-Erling Smørgrav *log_facility_ptr = (SyslogFacility) value;
1795511b41d2SMark Murray break;
1796511b41d2SMark Murray
1797511b41d2SMark Murray case sLogLevel:
1798d4af9e69SDag-Erling Smørgrav log_level_ptr = &options->log_level;
179919261079SEd Maste arg = argv_next(&ac, &av);
1800c2d3a559SKris Kennaway value = log_level_number(arg);
1801af12a3e7SDag-Erling Smørgrav if (value == SYSLOG_LEVEL_NOT_SET)
1802ca3176e7SBrian Feldman fatal("%.200s line %d: unsupported log level '%s'",
1803c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>");
18044f52dfbbSDag-Erling Smørgrav if (*activep && *log_level_ptr == -1)
1805d4af9e69SDag-Erling Smørgrav *log_level_ptr = (LogLevel) value;
1806511b41d2SMark Murray break;
1807511b41d2SMark Murray
180819261079SEd Maste case sLogVerbose:
180919261079SEd Maste found = options->num_log_verbose == 0;
181019261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
181119261079SEd Maste if (*arg == '\0') {
181219261079SEd Maste error("%s line %d: keyword %s empty argument",
181319261079SEd Maste filename, linenum, keyword);
181419261079SEd Maste goto out;
181519261079SEd Maste }
181619261079SEd Maste /* Allow "none" only in first position */
181719261079SEd Maste if (strcasecmp(arg, "none") == 0) {
1818a91a2465SEd Maste if (nstrs > 0 || ac > 0) {
181919261079SEd Maste error("%s line %d: keyword %s \"none\" "
182019261079SEd Maste "argument must appear alone.",
182119261079SEd Maste filename, linenum, keyword);
182219261079SEd Maste goto out;
182319261079SEd Maste }
182419261079SEd Maste }
182519261079SEd Maste opt_array_append(filename, linenum, keyword,
1826a91a2465SEd Maste &strs, &nstrs, arg);
1827a91a2465SEd Maste }
1828a91a2465SEd Maste if (nstrs == 0) {
1829a91a2465SEd Maste fatal("%s line %d: no %s specified",
1830a91a2465SEd Maste filename, linenum, keyword);
1831a91a2465SEd Maste }
1832a91a2465SEd Maste if (found && *activep) {
1833a91a2465SEd Maste options->log_verbose = strs;
1834a91a2465SEd Maste options->num_log_verbose = nstrs;
1835a91a2465SEd Maste strs = NULL; /* transferred */
1836a91a2465SEd Maste nstrs = 0;
183719261079SEd Maste }
183819261079SEd Maste break;
183919261079SEd Maste
184009958426SBrian Feldman case sAllowTcpForwarding:
184109958426SBrian Feldman intptr = &options->allow_tcp_forwarding;
18426888a9beSDag-Erling Smørgrav multistate_ptr = multistate_tcpfwd;
18436888a9beSDag-Erling Smørgrav goto parse_multistate;
184409958426SBrian Feldman
1845a0ee8cc6SDag-Erling Smørgrav case sAllowStreamLocalForwarding:
1846a0ee8cc6SDag-Erling Smørgrav intptr = &options->allow_streamlocal_forwarding;
1847a0ee8cc6SDag-Erling Smørgrav multistate_ptr = multistate_tcpfwd;
1848a0ee8cc6SDag-Erling Smørgrav goto parse_multistate;
1849a0ee8cc6SDag-Erling Smørgrav
1850d4af9e69SDag-Erling Smørgrav case sAllowAgentForwarding:
1851d4af9e69SDag-Erling Smørgrav intptr = &options->allow_agent_forwarding;
1852d4af9e69SDag-Erling Smørgrav goto parse_flag;
1853d4af9e69SDag-Erling Smørgrav
1854ca86bcf2SDag-Erling Smørgrav case sDisableForwarding:
1855ca86bcf2SDag-Erling Smørgrav intptr = &options->disable_forwarding;
1856ca86bcf2SDag-Erling Smørgrav goto parse_flag;
1857ca86bcf2SDag-Erling Smørgrav
1858511b41d2SMark Murray case sAllowUsers:
185919261079SEd Maste chararrayptr = &options->allow_users;
186019261079SEd Maste uintptr = &options->num_allow_users;
186119261079SEd Maste parse_allowdenyusers:
1862a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */
186319261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
186419261079SEd Maste if (*arg == '\0' ||
186519261079SEd Maste match_user(NULL, NULL, NULL, arg) == -1)
186619261079SEd Maste fatal("%s line %d: invalid %s pattern: \"%s\"",
186719261079SEd Maste filename, linenum, keyword, arg);
1868a91a2465SEd Maste found = 1;
1869462c32cbSDag-Erling Smørgrav if (!*activep)
1870462c32cbSDag-Erling Smørgrav continue;
187119261079SEd Maste opt_array_append(filename, linenum, keyword,
187219261079SEd Maste chararrayptr, uintptr, arg);
1873511b41d2SMark Murray }
1874a91a2465SEd Maste if (!found) {
1875a91a2465SEd Maste fatal("%s line %d: no %s specified",
1876a91a2465SEd Maste filename, linenum, keyword);
1877a91a2465SEd Maste }
1878511b41d2SMark Murray break;
1879511b41d2SMark Murray
1880511b41d2SMark Murray case sDenyUsers:
188119261079SEd Maste chararrayptr = &options->deny_users;
188219261079SEd Maste uintptr = &options->num_deny_users;
188319261079SEd Maste goto parse_allowdenyusers;
1884511b41d2SMark Murray
1885511b41d2SMark Murray case sAllowGroups:
188619261079SEd Maste chararrayptr = &options->allow_groups;
188719261079SEd Maste uintptr = &options->num_allow_groups;
1888a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */
188919261079SEd Maste parse_allowdenygroups:
189019261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
189119261079SEd Maste if (*arg == '\0')
189219261079SEd Maste fatal("%s line %d: empty %s pattern",
189319261079SEd Maste filename, linenum, keyword);
1894a91a2465SEd Maste found = 1;
1895462c32cbSDag-Erling Smørgrav if (!*activep)
1896462c32cbSDag-Erling Smørgrav continue;
189719261079SEd Maste opt_array_append(filename, linenum, keyword,
189819261079SEd Maste chararrayptr, uintptr, arg);
1899511b41d2SMark Murray }
1900a91a2465SEd Maste if (!found) {
1901a91a2465SEd Maste fatal("%s line %d: no %s specified",
1902a91a2465SEd Maste filename, linenum, keyword);
1903a91a2465SEd Maste }
1904511b41d2SMark Murray break;
1905511b41d2SMark Murray
1906511b41d2SMark Murray case sDenyGroups:
190719261079SEd Maste chararrayptr = &options->deny_groups;
190819261079SEd Maste uintptr = &options->num_deny_groups;
190919261079SEd Maste goto parse_allowdenygroups;
1910511b41d2SMark Murray
1911e8aafc91SKris Kennaway case sCiphers:
191219261079SEd Maste arg = argv_next(&ac, &av);
1913c2d3a559SKris Kennaway if (!arg || *arg == '\0')
191419261079SEd Maste fatal("%s line %d: %s missing argument.",
191519261079SEd Maste filename, linenum, keyword);
191619261079SEd Maste if (*arg != '-' &&
191719261079SEd Maste !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1918e8aafc91SKris Kennaway fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1919c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>");
1920e8aafc91SKris Kennaway if (options->ciphers == NULL)
1921c2d3a559SKris Kennaway options->ciphers = xstrdup(arg);
1922e8aafc91SKris Kennaway break;
1923e8aafc91SKris Kennaway
1924ca3176e7SBrian Feldman case sMacs:
192519261079SEd Maste arg = argv_next(&ac, &av);
1926ca3176e7SBrian Feldman if (!arg || *arg == '\0')
192719261079SEd Maste fatal("%s line %d: %s missing argument.",
192819261079SEd Maste filename, linenum, keyword);
192919261079SEd Maste if (*arg != '-' &&
193019261079SEd Maste !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1931ca3176e7SBrian Feldman fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1932ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>");
1933ca3176e7SBrian Feldman if (options->macs == NULL)
1934ca3176e7SBrian Feldman options->macs = xstrdup(arg);
1935ca3176e7SBrian Feldman break;
1936ca3176e7SBrian Feldman
19374a421b63SDag-Erling Smørgrav case sKexAlgorithms:
193819261079SEd Maste arg = argv_next(&ac, &av);
19394a421b63SDag-Erling Smørgrav if (!arg || *arg == '\0')
194019261079SEd Maste fatal("%s line %d: %s missing argument.",
194119261079SEd Maste filename, linenum, keyword);
1942d93a896eSDag-Erling Smørgrav if (*arg != '-' &&
194319261079SEd Maste !kex_names_valid(*arg == '+' || *arg == '^' ?
194419261079SEd Maste arg + 1 : arg))
19454a421b63SDag-Erling Smørgrav fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
19464a421b63SDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>");
19474a421b63SDag-Erling Smørgrav if (options->kex_algorithms == NULL)
19484a421b63SDag-Erling Smørgrav options->kex_algorithms = xstrdup(arg);
19494a421b63SDag-Erling Smørgrav break;
19504a421b63SDag-Erling Smørgrav
1951c2d3a559SKris Kennaway case sSubsystem:
195219261079SEd Maste arg = argv_next(&ac, &av);
1953c2d3a559SKris Kennaway if (!arg || *arg == '\0')
195419261079SEd Maste fatal("%s line %d: %s missing argument.",
195519261079SEd Maste filename, linenum, keyword);
1956333ee039SDag-Erling Smørgrav if (!*activep) {
1957edf85781SEd Maste argv_consume(&ac);
1958333ee039SDag-Erling Smørgrav break;
1959333ee039SDag-Erling Smørgrav }
1960edf85781SEd Maste found = 0;
1961edf85781SEd Maste for (i = 0; i < options->num_subsystems; i++) {
1962edf85781SEd Maste if (strcmp(arg, options->subsystem_name[i]) == 0) {
1963edf85781SEd Maste found = 1;
1964edf85781SEd Maste break;
1965edf85781SEd Maste }
1966edf85781SEd Maste }
1967edf85781SEd Maste if (found) {
1968edf85781SEd Maste debug("%s line %d: Subsystem '%s' already defined.",
1969edf85781SEd Maste filename, linenum, arg);
1970edf85781SEd Maste argv_consume(&ac);
1971edf85781SEd Maste break;
1972edf85781SEd Maste }
1973edf85781SEd Maste options->subsystem_name = xrecallocarray(
1974edf85781SEd Maste options->subsystem_name, options->num_subsystems,
1975edf85781SEd Maste options->num_subsystems + 1,
1976edf85781SEd Maste sizeof(*options->subsystem_name));
1977edf85781SEd Maste options->subsystem_command = xrecallocarray(
1978edf85781SEd Maste options->subsystem_command, options->num_subsystems,
1979edf85781SEd Maste options->num_subsystems + 1,
1980edf85781SEd Maste sizeof(*options->subsystem_command));
1981edf85781SEd Maste options->subsystem_args = xrecallocarray(
1982edf85781SEd Maste options->subsystem_args, options->num_subsystems,
1983edf85781SEd Maste options->num_subsystems + 1,
1984edf85781SEd Maste sizeof(*options->subsystem_args));
1985c2d3a559SKris Kennaway options->subsystem_name[options->num_subsystems] = xstrdup(arg);
198619261079SEd Maste arg = argv_next(&ac, &av);
1987edf85781SEd Maste if (!arg || *arg == '\0') {
1988c2d3a559SKris Kennaway fatal("%s line %d: Missing subsystem command.",
1989c2d3a559SKris Kennaway filename, linenum);
1990333ee039SDag-Erling Smørgrav }
1991edf85781SEd Maste options->subsystem_command[options->num_subsystems] =
1992edf85781SEd Maste xstrdup(arg);
1993edf85781SEd Maste /* Collect arguments (separate to executable) */
1994edf85781SEd Maste arg = argv_assemble(1, &arg); /* quote command correctly */
1995edf85781SEd Maste arg2 = argv_assemble(ac, av); /* rest of command */
1996edf85781SEd Maste xasprintf(&options->subsystem_args[options->num_subsystems],
1997a91a2465SEd Maste "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2);
1998edf85781SEd Maste free(arg2);
19993d9fd9fcSEd Maste free(arg);
2000edf85781SEd Maste argv_consume(&ac);
2001c2d3a559SKris Kennaway options->num_subsystems++;
2002c2d3a559SKris Kennaway break;
2003c2d3a559SKris Kennaway
2004c2d3a559SKris Kennaway case sMaxStartups:
200519261079SEd Maste arg = argv_next(&ac, &av);
2006c2d3a559SKris Kennaway if (!arg || *arg == '\0')
200719261079SEd Maste fatal("%s line %d: %s missing argument.",
200819261079SEd Maste filename, linenum, keyword);
2009af12a3e7SDag-Erling Smørgrav if ((n = sscanf(arg, "%d:%d:%d",
2010c2d3a559SKris Kennaway &options->max_startups_begin,
2011c2d3a559SKris Kennaway &options->max_startups_rate,
2012af12a3e7SDag-Erling Smørgrav &options->max_startups)) == 3) {
2013c2d3a559SKris Kennaway if (options->max_startups_begin >
2014c2d3a559SKris Kennaway options->max_startups ||
2015c2d3a559SKris Kennaway options->max_startups_rate > 100 ||
2016c2d3a559SKris Kennaway options->max_startups_rate < 1)
201719261079SEd Maste fatal("%s line %d: Invalid %s spec.",
201819261079SEd Maste filename, linenum, keyword);
2019af12a3e7SDag-Erling Smørgrav } else if (n != 1)
202019261079SEd Maste fatal("%s line %d: Invalid %s spec.",
202119261079SEd Maste filename, linenum, keyword);
2022af12a3e7SDag-Erling Smørgrav else
2023af12a3e7SDag-Erling Smørgrav options->max_startups = options->max_startups_begin;
2024f374ba41SEd Maste if (options->max_startups <= 0 ||
2025f374ba41SEd Maste options->max_startups_begin <= 0)
2026f374ba41SEd Maste fatal("%s line %d: Invalid %s spec.",
2027f374ba41SEd Maste filename, linenum, keyword);
2028933ca70fSBrian Feldman break;
2029933ca70fSBrian Feldman
203019261079SEd Maste case sPerSourceNetBlockSize:
203119261079SEd Maste arg = argv_next(&ac, &av);
203219261079SEd Maste if (!arg || *arg == '\0')
203319261079SEd Maste fatal("%s line %d: %s missing argument.",
203419261079SEd Maste filename, linenum, keyword);
203519261079SEd Maste switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
203619261079SEd Maste case 2:
203719261079SEd Maste if (value2 < 0 || value2 > 128)
203819261079SEd Maste n = -1;
203919261079SEd Maste /* FALLTHROUGH */
204019261079SEd Maste case 1:
204119261079SEd Maste if (value < 0 || value > 32)
204219261079SEd Maste n = -1;
204319261079SEd Maste }
204419261079SEd Maste if (n != 1 && n != 2)
204519261079SEd Maste fatal("%s line %d: Invalid %s spec.",
204619261079SEd Maste filename, linenum, keyword);
204719261079SEd Maste if (*activep) {
204819261079SEd Maste options->per_source_masklen_ipv4 = value;
204919261079SEd Maste options->per_source_masklen_ipv6 = value2;
205019261079SEd Maste }
205119261079SEd Maste break;
205219261079SEd Maste
205319261079SEd Maste case sPerSourceMaxStartups:
205419261079SEd Maste arg = argv_next(&ac, &av);
205519261079SEd Maste if (!arg || *arg == '\0')
205619261079SEd Maste fatal("%s line %d: %s missing argument.",
205719261079SEd Maste filename, linenum, keyword);
205819261079SEd Maste if (strcmp(arg, "none") == 0) { /* no limit */
205919261079SEd Maste value = INT_MAX;
206019261079SEd Maste } else {
206119261079SEd Maste if ((errstr = atoi_err(arg, &value)) != NULL)
206219261079SEd Maste fatal("%s line %d: %s integer value %s.",
206319261079SEd Maste filename, linenum, keyword, errstr);
206419261079SEd Maste }
2065edf85781SEd Maste if (*activep && options->per_source_max_startups == -1)
206619261079SEd Maste options->per_source_max_startups = value;
206719261079SEd Maste break;
206819261079SEd Maste
20690fdf8faeSEd Maste case sPerSourcePenaltyExemptList:
20700fdf8faeSEd Maste charptr = &options->per_source_penalty_exempt;
20710fdf8faeSEd Maste arg = argv_next(&ac, &av);
20720fdf8faeSEd Maste if (!arg || *arg == '\0')
20730fdf8faeSEd Maste fatal("%s line %d: missing argument.",
20740fdf8faeSEd Maste filename, linenum);
20750fdf8faeSEd Maste if (addr_match_list(NULL, arg) != 0) {
20760fdf8faeSEd Maste fatal("%s line %d: keyword %s "
20770fdf8faeSEd Maste "invalid address argument.",
20780fdf8faeSEd Maste filename, linenum, keyword);
20790fdf8faeSEd Maste }
20800fdf8faeSEd Maste if (*activep && *charptr == NULL)
20810fdf8faeSEd Maste *charptr = xstrdup(arg);
20820fdf8faeSEd Maste break;
20830fdf8faeSEd Maste
20840fdf8faeSEd Maste case sPerSourcePenalties:
20850fdf8faeSEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
20860fdf8faeSEd Maste found = 1;
20870fdf8faeSEd Maste value = -1;
20880fdf8faeSEd Maste value2 = 0;
20890fdf8faeSEd Maste p = NULL;
20900fdf8faeSEd Maste /* Allow no/yes only in first position */
20910fdf8faeSEd Maste if (strcasecmp(arg, "no") == 0 ||
20920fdf8faeSEd Maste (value2 = (strcasecmp(arg, "yes") == 0))) {
20930fdf8faeSEd Maste if (ac > 0) {
20940fdf8faeSEd Maste fatal("%s line %d: keyword %s \"%s\" "
20950fdf8faeSEd Maste "argument must appear alone.",
20960fdf8faeSEd Maste filename, linenum, keyword, arg);
20970fdf8faeSEd Maste }
20980fdf8faeSEd Maste if (*activep &&
20990fdf8faeSEd Maste options->per_source_penalty.enabled == -1)
21000fdf8faeSEd Maste options->per_source_penalty.enabled = value2;
21010fdf8faeSEd Maste continue;
21020fdf8faeSEd Maste } else if (strncmp(arg, "crash:", 6) == 0) {
21030fdf8faeSEd Maste p = arg + 6;
21040fdf8faeSEd Maste intptr = &options->per_source_penalty.penalty_crash;
21050fdf8faeSEd Maste } else if (strncmp(arg, "authfail:", 9) == 0) {
21060fdf8faeSEd Maste p = arg + 9;
21070fdf8faeSEd Maste intptr = &options->per_source_penalty.penalty_authfail;
21080fdf8faeSEd Maste } else if (strncmp(arg, "noauth:", 7) == 0) {
21090fdf8faeSEd Maste p = arg + 7;
21100fdf8faeSEd Maste intptr = &options->per_source_penalty.penalty_noauth;
21110fdf8faeSEd Maste } else if (strncmp(arg, "grace-exceeded:", 15) == 0) {
21120fdf8faeSEd Maste p = arg + 15;
21130fdf8faeSEd Maste intptr = &options->per_source_penalty.penalty_grace;
21143d9fd9fcSEd Maste } else if (strncmp(arg, "refuseconnection:", 17) == 0) {
21153d9fd9fcSEd Maste p = arg + 17;
21163d9fd9fcSEd Maste intptr = &options->per_source_penalty.penalty_refuseconnection;
21170fdf8faeSEd Maste } else if (strncmp(arg, "max:", 4) == 0) {
21180fdf8faeSEd Maste p = arg + 4;
21190fdf8faeSEd Maste intptr = &options->per_source_penalty.penalty_max;
21200fdf8faeSEd Maste } else if (strncmp(arg, "min:", 4) == 0) {
21210fdf8faeSEd Maste p = arg + 4;
21220fdf8faeSEd Maste intptr = &options->per_source_penalty.penalty_min;
21230fdf8faeSEd Maste } else if (strncmp(arg, "max-sources4:", 13) == 0) {
21240fdf8faeSEd Maste intptr = &options->per_source_penalty.max_sources4;
21250fdf8faeSEd Maste if ((errstr = atoi_err(arg+13, &value)) != NULL)
21260fdf8faeSEd Maste fatal("%s line %d: %s value %s.",
21270fdf8faeSEd Maste filename, linenum, keyword, errstr);
21280fdf8faeSEd Maste } else if (strncmp(arg, "max-sources6:", 13) == 0) {
21290fdf8faeSEd Maste intptr = &options->per_source_penalty.max_sources6;
21300fdf8faeSEd Maste if ((errstr = atoi_err(arg+13, &value)) != NULL)
21310fdf8faeSEd Maste fatal("%s line %d: %s value %s.",
21320fdf8faeSEd Maste filename, linenum, keyword, errstr);
21330fdf8faeSEd Maste } else if (strcmp(arg, "overflow:deny-all") == 0) {
21340fdf8faeSEd Maste intptr = &options->per_source_penalty.overflow_mode;
21350fdf8faeSEd Maste value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
21360fdf8faeSEd Maste } else if (strcmp(arg, "overflow:permissive") == 0) {
21370fdf8faeSEd Maste intptr = &options->per_source_penalty.overflow_mode;
21380fdf8faeSEd Maste value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
21390fdf8faeSEd Maste } else if (strcmp(arg, "overflow6:deny-all") == 0) {
21400fdf8faeSEd Maste intptr = &options->per_source_penalty.overflow_mode6;
21410fdf8faeSEd Maste value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
21420fdf8faeSEd Maste } else if (strcmp(arg, "overflow6:permissive") == 0) {
21430fdf8faeSEd Maste intptr = &options->per_source_penalty.overflow_mode6;
21440fdf8faeSEd Maste value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
21450fdf8faeSEd Maste } else {
21460fdf8faeSEd Maste fatal("%s line %d: unsupported %s keyword %s",
21470fdf8faeSEd Maste filename, linenum, keyword, arg);
21480fdf8faeSEd Maste }
21490fdf8faeSEd Maste /* If no value was parsed above, assume it's a time */
21500fdf8faeSEd Maste if (value == -1 && (value = convtime(p)) == -1) {
21510fdf8faeSEd Maste fatal("%s line %d: invalid %s time value.",
21520fdf8faeSEd Maste filename, linenum, keyword);
21530fdf8faeSEd Maste }
21540fdf8faeSEd Maste if (*activep && *intptr == -1) {
21550fdf8faeSEd Maste *intptr = value;
21560fdf8faeSEd Maste /* any option implicitly enables penalties */
21570fdf8faeSEd Maste options->per_source_penalty.enabled = 1;
21580fdf8faeSEd Maste }
21590fdf8faeSEd Maste }
21600fdf8faeSEd Maste if (!found) {
21610fdf8faeSEd Maste fatal("%s line %d: no %s specified",
21620fdf8faeSEd Maste filename, linenum, keyword);
21630fdf8faeSEd Maste }
21640fdf8faeSEd Maste break;
21650fdf8faeSEd Maste
216621e764dfSDag-Erling Smørgrav case sMaxAuthTries:
216721e764dfSDag-Erling Smørgrav intptr = &options->max_authtries;
216821e764dfSDag-Erling Smørgrav goto parse_int;
216921e764dfSDag-Erling Smørgrav
2170d4af9e69SDag-Erling Smørgrav case sMaxSessions:
2171d4af9e69SDag-Erling Smørgrav intptr = &options->max_sessions;
2172d4af9e69SDag-Erling Smørgrav goto parse_int;
2173d4af9e69SDag-Erling Smørgrav
2174ca3176e7SBrian Feldman case sBanner:
2175ca3176e7SBrian Feldman charptr = &options->banner;
2176ca3176e7SBrian Feldman goto parse_filename;
2177d4af9e69SDag-Erling Smørgrav
2178af12a3e7SDag-Erling Smørgrav /*
2179af12a3e7SDag-Erling Smørgrav * These options can contain %X options expanded at
2180af12a3e7SDag-Erling Smørgrav * connect time, so that you can specify paths like:
2181af12a3e7SDag-Erling Smørgrav *
2182af12a3e7SDag-Erling Smørgrav * AuthorizedKeysFile /etc/ssh_keys/%u
2183af12a3e7SDag-Erling Smørgrav */
2184af12a3e7SDag-Erling Smørgrav case sAuthorizedKeysFile:
2185a91a2465SEd Maste found = options->num_authkeys_files == 0;
218619261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
218719261079SEd Maste if (*arg == '\0') {
218819261079SEd Maste error("%s line %d: keyword %s empty argument",
218919261079SEd Maste filename, linenum, keyword);
219019261079SEd Maste goto out;
219119261079SEd Maste }
219219261079SEd Maste arg2 = tilde_expand_filename(arg, getuid());
219319261079SEd Maste opt_array_append(filename, linenum, keyword,
2194a91a2465SEd Maste &strs, &nstrs, arg2);
219519261079SEd Maste free(arg2);
2196e146993eSDag-Erling Smørgrav }
2197a91a2465SEd Maste if (nstrs == 0) {
2198a91a2465SEd Maste fatal("%s line %d: no %s specified",
2199a91a2465SEd Maste filename, linenum, keyword);
2200a91a2465SEd Maste }
2201a91a2465SEd Maste if (found && *activep) {
2202a91a2465SEd Maste options->authorized_keys_files = strs;
2203a91a2465SEd Maste options->num_authkeys_files = nstrs;
2204a91a2465SEd Maste strs = NULL; /* transferred */
2205a91a2465SEd Maste nstrs = 0;
2206a91a2465SEd Maste }
220719261079SEd Maste break;
2208e146993eSDag-Erling Smørgrav
2209e2f6069cSDag-Erling Smørgrav case sAuthorizedPrincipalsFile:
2210e2f6069cSDag-Erling Smørgrav charptr = &options->authorized_principals_file;
221119261079SEd Maste arg = argv_next(&ac, &av);
22128ad9b54aSDag-Erling Smørgrav if (!arg || *arg == '\0')
221319261079SEd Maste fatal("%s line %d: %s missing argument.",
221419261079SEd Maste filename, linenum, keyword);
22158ad9b54aSDag-Erling Smørgrav if (*activep && *charptr == NULL) {
22168ad9b54aSDag-Erling Smørgrav *charptr = tilde_expand_filename(arg, getuid());
22178ad9b54aSDag-Erling Smørgrav /* increase optional counter */
22188ad9b54aSDag-Erling Smørgrav if (intptr != NULL)
22198ad9b54aSDag-Erling Smørgrav *intptr = *intptr + 1;
22208ad9b54aSDag-Erling Smørgrav }
22218ad9b54aSDag-Erling Smørgrav break;
2222af12a3e7SDag-Erling Smørgrav
2223ca3176e7SBrian Feldman case sClientAliveInterval:
2224ca3176e7SBrian Feldman intptr = &options->client_alive_interval;
2225af12a3e7SDag-Erling Smørgrav goto parse_time;
2226af12a3e7SDag-Erling Smørgrav
2227ca3176e7SBrian Feldman case sClientAliveCountMax:
2228ca3176e7SBrian Feldman intptr = &options->client_alive_count_max;
2229ca3176e7SBrian Feldman goto parse_int;
2230af12a3e7SDag-Erling Smørgrav
223121e764dfSDag-Erling Smørgrav case sAcceptEnv:
2232a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */
223319261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
223419261079SEd Maste if (*arg == '\0' || strchr(arg, '=') != NULL)
223521e764dfSDag-Erling Smørgrav fatal("%s line %d: Invalid environment name.",
223621e764dfSDag-Erling Smørgrav filename, linenum);
2237a91a2465SEd Maste found = 1;
2238333ee039SDag-Erling Smørgrav if (!*activep)
2239462c32cbSDag-Erling Smørgrav continue;
224019261079SEd Maste opt_array_append(filename, linenum, keyword,
224147dd1d1bSDag-Erling Smørgrav &options->accept_env, &options->num_accept_env,
224247dd1d1bSDag-Erling Smørgrav arg);
224321e764dfSDag-Erling Smørgrav }
2244a91a2465SEd Maste if (!found) {
2245a91a2465SEd Maste fatal("%s line %d: no %s specified",
2246a91a2465SEd Maste filename, linenum, keyword);
2247a91a2465SEd Maste }
224821e764dfSDag-Erling Smørgrav break;
224921e764dfSDag-Erling Smørgrav
2250190cef3dSDag-Erling Smørgrav case sSetEnv:
2251a91a2465SEd Maste found = options->num_setenv == 0;
225219261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
225319261079SEd Maste if (*arg == '\0' || strchr(arg, '=') == NULL)
2254190cef3dSDag-Erling Smørgrav fatal("%s line %d: Invalid environment.",
2255190cef3dSDag-Erling Smørgrav filename, linenum);
2256a91a2465SEd Maste if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
225738a52bd3SEd Maste debug2("%s line %d: ignoring duplicate env "
225838a52bd3SEd Maste "name \"%.64s\"", filename, linenum, arg);
225938a52bd3SEd Maste continue;
226038a52bd3SEd Maste }
226119261079SEd Maste opt_array_append(filename, linenum, keyword,
2262a91a2465SEd Maste &strs, &nstrs, arg);
2263a91a2465SEd Maste }
2264a91a2465SEd Maste if (nstrs == 0) {
2265a91a2465SEd Maste fatal("%s line %d: no %s specified",
2266a91a2465SEd Maste filename, linenum, keyword);
2267a91a2465SEd Maste }
2268a91a2465SEd Maste if (found && *activep) {
2269a91a2465SEd Maste options->setenv = strs;
2270a91a2465SEd Maste options->num_setenv = nstrs;
2271a91a2465SEd Maste strs = NULL; /* transferred */
2272a91a2465SEd Maste nstrs = 0;
2273190cef3dSDag-Erling Smørgrav }
2274190cef3dSDag-Erling Smørgrav break;
2275190cef3dSDag-Erling Smørgrav
2276b74df5b2SDag-Erling Smørgrav case sPermitTunnel:
2277b74df5b2SDag-Erling Smørgrav intptr = &options->permit_tun;
227819261079SEd Maste arg = argv_next(&ac, &av);
2279b74df5b2SDag-Erling Smørgrav if (!arg || *arg == '\0')
228019261079SEd Maste fatal("%s line %d: %s missing argument.",
228119261079SEd Maste filename, linenum, keyword);
2282d4af9e69SDag-Erling Smørgrav value = -1;
2283d4af9e69SDag-Erling Smørgrav for (i = 0; tunmode_desc[i].val != -1; i++)
2284d4af9e69SDag-Erling Smørgrav if (strcmp(tunmode_desc[i].text, arg) == 0) {
2285d4af9e69SDag-Erling Smørgrav value = tunmode_desc[i].val;
2286d4af9e69SDag-Erling Smørgrav break;
2287d4af9e69SDag-Erling Smørgrav }
2288d4af9e69SDag-Erling Smørgrav if (value == -1)
228919261079SEd Maste fatal("%s line %d: bad %s argument %s",
229019261079SEd Maste filename, linenum, keyword, arg);
2291557f75e5SDag-Erling Smørgrav if (*activep && *intptr == -1)
2292b74df5b2SDag-Erling Smørgrav *intptr = value;
2293b74df5b2SDag-Erling Smørgrav break;
2294b74df5b2SDag-Erling Smørgrav
229519261079SEd Maste case sInclude:
229619261079SEd Maste if (cmdline) {
229719261079SEd Maste fatal("Include directive not supported as a "
229819261079SEd Maste "command-line option");
229919261079SEd Maste }
230019261079SEd Maste value = 0;
230119261079SEd Maste while ((arg2 = argv_next(&ac, &av)) != NULL) {
230219261079SEd Maste if (*arg2 == '\0') {
230319261079SEd Maste error("%s line %d: keyword %s empty argument",
230419261079SEd Maste filename, linenum, keyword);
230519261079SEd Maste goto out;
230619261079SEd Maste }
230719261079SEd Maste value++;
230819261079SEd Maste found = 0;
230919261079SEd Maste if (*arg2 != '/' && *arg2 != '~') {
231019261079SEd Maste xasprintf(&arg, "%s/%s", SSHDIR, arg2);
231119261079SEd Maste } else
231219261079SEd Maste arg = xstrdup(arg2);
231319261079SEd Maste
231419261079SEd Maste /*
231519261079SEd Maste * Don't let included files clobber the containing
231619261079SEd Maste * file's Match state.
231719261079SEd Maste */
231819261079SEd Maste oactive = *activep;
231919261079SEd Maste
232019261079SEd Maste /* consult cache of include files */
232119261079SEd Maste TAILQ_FOREACH(item, includes, entry) {
232219261079SEd Maste if (strcmp(item->selector, arg) != 0)
232319261079SEd Maste continue;
232419261079SEd Maste if (item->filename != NULL) {
232519261079SEd Maste parse_server_config_depth(options,
232619261079SEd Maste item->filename, item->contents,
232719261079SEd Maste includes, connectinfo,
232819261079SEd Maste (*inc_flags & SSHCFG_MATCH_ONLY
232919261079SEd Maste ? SSHCFG_MATCH_ONLY : (oactive
233019261079SEd Maste ? 0 : SSHCFG_NEVERMATCH)),
233119261079SEd Maste activep, depth + 1);
233219261079SEd Maste }
233319261079SEd Maste found = 1;
233419261079SEd Maste *activep = oactive;
233519261079SEd Maste }
233619261079SEd Maste if (found != 0) {
233719261079SEd Maste free(arg);
233819261079SEd Maste continue;
233919261079SEd Maste }
234019261079SEd Maste
234119261079SEd Maste /* requested glob was not in cache */
234219261079SEd Maste debug2("%s line %d: new include %s",
234319261079SEd Maste filename, linenum, arg);
234419261079SEd Maste if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
234519261079SEd Maste if (r != GLOB_NOMATCH) {
234619261079SEd Maste fatal("%s line %d: include \"%s\" glob "
234719261079SEd Maste "failed", filename, linenum, arg);
234819261079SEd Maste }
234919261079SEd Maste /*
235019261079SEd Maste * If no entry matched then record a
235119261079SEd Maste * placeholder to skip later glob calls.
235219261079SEd Maste */
235319261079SEd Maste debug2("%s line %d: no match for %s",
235419261079SEd Maste filename, linenum, arg);
235519261079SEd Maste item = xcalloc(1, sizeof(*item));
235619261079SEd Maste item->selector = strdup(arg);
235719261079SEd Maste TAILQ_INSERT_TAIL(includes,
235819261079SEd Maste item, entry);
235919261079SEd Maste }
236019261079SEd Maste if (gbuf.gl_pathc > INT_MAX)
236119261079SEd Maste fatal_f("too many glob results");
236219261079SEd Maste for (n = 0; n < (int)gbuf.gl_pathc; n++) {
236319261079SEd Maste debug2("%s line %d: including %s",
236419261079SEd Maste filename, linenum, gbuf.gl_pathv[n]);
236519261079SEd Maste item = xcalloc(1, sizeof(*item));
236619261079SEd Maste item->selector = strdup(arg);
236719261079SEd Maste item->filename = strdup(gbuf.gl_pathv[n]);
236819261079SEd Maste if ((item->contents = sshbuf_new()) == NULL)
236919261079SEd Maste fatal_f("sshbuf_new failed");
237019261079SEd Maste load_server_config(item->filename,
237119261079SEd Maste item->contents);
237219261079SEd Maste parse_server_config_depth(options,
237319261079SEd Maste item->filename, item->contents,
237419261079SEd Maste includes, connectinfo,
237519261079SEd Maste (*inc_flags & SSHCFG_MATCH_ONLY
237619261079SEd Maste ? SSHCFG_MATCH_ONLY : (oactive
237719261079SEd Maste ? 0 : SSHCFG_NEVERMATCH)),
237819261079SEd Maste activep, depth + 1);
237919261079SEd Maste *activep = oactive;
238019261079SEd Maste TAILQ_INSERT_TAIL(includes, item, entry);
238119261079SEd Maste }
238219261079SEd Maste globfree(&gbuf);
238319261079SEd Maste free(arg);
238419261079SEd Maste }
238519261079SEd Maste if (value == 0) {
238619261079SEd Maste fatal("%s line %d: %s missing filename argument",
238719261079SEd Maste filename, linenum, keyword);
238819261079SEd Maste }
238919261079SEd Maste break;
239019261079SEd Maste
2391333ee039SDag-Erling Smørgrav case sMatch:
2392333ee039SDag-Erling Smørgrav if (cmdline)
2393333ee039SDag-Erling Smørgrav fatal("Match directive not supported as a command-line "
2394333ee039SDag-Erling Smørgrav "option");
23953d9fd9fcSEd Maste value = match_cfg_line(str, &ac, &av, linenum,
239619261079SEd Maste (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2397333ee039SDag-Erling Smørgrav if (value < 0)
2398333ee039SDag-Erling Smørgrav fatal("%s line %d: Bad Match condition", filename,
2399333ee039SDag-Erling Smørgrav linenum);
240019261079SEd Maste *activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
240119261079SEd Maste /*
240219261079SEd Maste * The MATCH_ONLY flag is applicable only until the first
240319261079SEd Maste * match block.
240419261079SEd Maste */
240519261079SEd Maste *inc_flags &= ~SSHCFG_MATCH_ONLY;
2406333ee039SDag-Erling Smørgrav break;
2407333ee039SDag-Erling Smørgrav
2408190cef3dSDag-Erling Smørgrav case sPermitListen:
2409333ee039SDag-Erling Smørgrav case sPermitOpen:
2410190cef3dSDag-Erling Smørgrav if (opcode == sPermitListen) {
2411190cef3dSDag-Erling Smørgrav uintptr = &options->num_permitted_listens;
2412190cef3dSDag-Erling Smørgrav chararrayptr = &options->permitted_listens;
2413190cef3dSDag-Erling Smørgrav } else {
2414190cef3dSDag-Erling Smørgrav uintptr = &options->num_permitted_opens;
2415190cef3dSDag-Erling Smørgrav chararrayptr = &options->permitted_opens;
2416190cef3dSDag-Erling Smørgrav }
2417a91a2465SEd Maste found = *uintptr == 0;
2418a91a2465SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
2419a91a2465SEd Maste if (strcmp(arg, "any") == 0 ||
2420a91a2465SEd Maste strcmp(arg, "none") == 0) {
2421a91a2465SEd Maste if (nstrs != 0) {
2422a91a2465SEd Maste fatal("%s line %d: %s must appear "
2423a91a2465SEd Maste "alone on a %s line.",
2424a91a2465SEd Maste filename, linenum, arg, keyword);
2425462c32cbSDag-Erling Smørgrav }
2426a91a2465SEd Maste opt_array_append(filename, linenum, keyword,
2427a91a2465SEd Maste &strs, &nstrs, arg);
2428a91a2465SEd Maste continue;
2429462c32cbSDag-Erling Smørgrav }
2430a91a2465SEd Maste
2431190cef3dSDag-Erling Smørgrav if (opcode == sPermitListen &&
2432190cef3dSDag-Erling Smørgrav strchr(arg, ':') == NULL) {
2433190cef3dSDag-Erling Smørgrav /*
2434190cef3dSDag-Erling Smørgrav * Allow bare port number for PermitListen
2435190cef3dSDag-Erling Smørgrav * to indicate a wildcard listen host.
2436190cef3dSDag-Erling Smørgrav */
2437190cef3dSDag-Erling Smørgrav xasprintf(&arg2, "*:%s", arg);
2438190cef3dSDag-Erling Smørgrav } else {
24394f52dfbbSDag-Erling Smørgrav arg2 = xstrdup(arg);
24401323ec57SEd Maste p = hpdelim(&arg);
24411323ec57SEd Maste if (p == NULL) {
244219261079SEd Maste fatal("%s line %d: %s missing host",
244319261079SEd Maste filename, linenum, keyword);
2444190cef3dSDag-Erling Smørgrav }
2445333ee039SDag-Erling Smørgrav p = cleanhostname(p);
2446190cef3dSDag-Erling Smørgrav }
2447190cef3dSDag-Erling Smørgrav if (arg == NULL ||
2448190cef3dSDag-Erling Smørgrav ((port = permitopen_port(arg)) < 0)) {
244919261079SEd Maste fatal("%s line %d: %s bad port number",
245019261079SEd Maste filename, linenum, keyword);
2451190cef3dSDag-Erling Smørgrav }
245219261079SEd Maste opt_array_append(filename, linenum, keyword,
2453a91a2465SEd Maste &strs, &nstrs, arg2);
24544f52dfbbSDag-Erling Smørgrav free(arg2);
2455333ee039SDag-Erling Smørgrav }
2456a91a2465SEd Maste if (nstrs == 0) {
2457a91a2465SEd Maste fatal("%s line %d: %s missing argument.",
2458a91a2465SEd Maste filename, linenum, keyword);
2459a91a2465SEd Maste }
2460a91a2465SEd Maste if (found && *activep) {
2461a91a2465SEd Maste *chararrayptr = strs;
2462a91a2465SEd Maste *uintptr = nstrs;
2463a91a2465SEd Maste strs = NULL; /* transferred */
2464a91a2465SEd Maste nstrs = 0;
2465a91a2465SEd Maste }
2466333ee039SDag-Erling Smørgrav break;
2467333ee039SDag-Erling Smørgrav
2468333ee039SDag-Erling Smørgrav case sForceCommand:
246919261079SEd Maste if (str == NULL || *str == '\0')
247019261079SEd Maste fatal("%s line %d: %s missing argument.",
247119261079SEd Maste filename, linenum, keyword);
247219261079SEd Maste len = strspn(str, WHITESPACE);
2473333ee039SDag-Erling Smørgrav if (*activep && options->adm_forced_command == NULL)
247419261079SEd Maste options->adm_forced_command = xstrdup(str + len);
247519261079SEd Maste argv_consume(&ac);
247619261079SEd Maste break;
2477333ee039SDag-Erling Smørgrav
2478d4af9e69SDag-Erling Smørgrav case sChrootDirectory:
2479d4af9e69SDag-Erling Smørgrav charptr = &options->chroot_directory;
2480d4af9e69SDag-Erling Smørgrav
248119261079SEd Maste arg = argv_next(&ac, &av);
2482d4af9e69SDag-Erling Smørgrav if (!arg || *arg == '\0')
248319261079SEd Maste fatal("%s line %d: %s missing argument.",
248419261079SEd Maste filename, linenum, keyword);
2485d4af9e69SDag-Erling Smørgrav if (*activep && *charptr == NULL)
2486d4af9e69SDag-Erling Smørgrav *charptr = xstrdup(arg);
2487d4af9e69SDag-Erling Smørgrav break;
2488d4af9e69SDag-Erling Smørgrav
2489b15c8340SDag-Erling Smørgrav case sTrustedUserCAKeys:
2490b15c8340SDag-Erling Smørgrav charptr = &options->trusted_user_ca_keys;
2491b15c8340SDag-Erling Smørgrav goto parse_filename;
2492b15c8340SDag-Erling Smørgrav
2493b15c8340SDag-Erling Smørgrav case sRevokedKeys:
2494b15c8340SDag-Erling Smørgrav charptr = &options->revoked_keys_file;
2495b15c8340SDag-Erling Smørgrav goto parse_filename;
2496b15c8340SDag-Erling Smørgrav
249719261079SEd Maste case sSecurityKeyProvider:
249819261079SEd Maste charptr = &options->sk_provider;
249919261079SEd Maste arg = argv_next(&ac, &av);
250019261079SEd Maste if (!arg || *arg == '\0')
250119261079SEd Maste fatal("%s line %d: %s missing argument.",
250219261079SEd Maste filename, linenum, keyword);
250319261079SEd Maste if (*activep && *charptr == NULL) {
250419261079SEd Maste *charptr = strcasecmp(arg, "internal") == 0 ?
250519261079SEd Maste xstrdup(arg) : derelativise_path(arg);
250619261079SEd Maste /* increase optional counter */
250719261079SEd Maste if (intptr != NULL)
250819261079SEd Maste *intptr = *intptr + 1;
250919261079SEd Maste }
251019261079SEd Maste break;
251119261079SEd Maste
25124a421b63SDag-Erling Smørgrav case sIPQoS:
251319261079SEd Maste arg = argv_next(&ac, &av);
251419261079SEd Maste if (!arg || *arg == '\0')
251519261079SEd Maste fatal("%s line %d: %s missing argument.",
251619261079SEd Maste filename, linenum, keyword);
25174a421b63SDag-Erling Smørgrav if ((value = parse_ipqos(arg)) == -1)
251819261079SEd Maste fatal("%s line %d: Bad %s value: %s",
251919261079SEd Maste filename, linenum, keyword, arg);
252019261079SEd Maste arg = argv_next(&ac, &av);
25214a421b63SDag-Erling Smørgrav if (arg == NULL)
25224a421b63SDag-Erling Smørgrav value2 = value;
25234a421b63SDag-Erling Smørgrav else if ((value2 = parse_ipqos(arg)) == -1)
252419261079SEd Maste fatal("%s line %d: Bad %s value: %s",
252519261079SEd Maste filename, linenum, keyword, arg);
25264a421b63SDag-Erling Smørgrav if (*activep) {
25274a421b63SDag-Erling Smørgrav options->ip_qos_interactive = value;
25284a421b63SDag-Erling Smørgrav options->ip_qos_bulk = value2;
25294a421b63SDag-Erling Smørgrav }
25304a421b63SDag-Erling Smørgrav break;
25314a421b63SDag-Erling Smørgrav
2532db58a8e4SDag-Erling Smørgrav case sVersionAddendum:
253319261079SEd Maste if (str == NULL || *str == '\0')
253419261079SEd Maste fatal("%s line %d: %s missing argument.",
253519261079SEd Maste filename, linenum, keyword);
253619261079SEd Maste len = strspn(str, WHITESPACE);
253719261079SEd Maste if (strchr(str + len, '\r') != NULL) {
253819261079SEd Maste fatal("%.200s line %d: Invalid %s argument",
253919261079SEd Maste filename, linenum, keyword);
2540462c32cbSDag-Erling Smørgrav }
254119261079SEd Maste if ((arg = strchr(line, '#')) != NULL) {
254219261079SEd Maste *arg = '\0';
254319261079SEd Maste rtrim(line);
254419261079SEd Maste }
254519261079SEd Maste if (*activep && options->version_addendum == NULL) {
254619261079SEd Maste if (strcasecmp(str + len, "none") == 0)
254719261079SEd Maste options->version_addendum = xstrdup("");
254819261079SEd Maste else
254919261079SEd Maste options->version_addendum = xstrdup(str + len);
255019261079SEd Maste }
255119261079SEd Maste argv_consume(&ac);
255219261079SEd Maste break;
2553db58a8e4SDag-Erling Smørgrav
25546888a9beSDag-Erling Smørgrav case sAuthorizedKeysCommand:
255519261079SEd Maste charptr = &options->authorized_keys_command;
255619261079SEd Maste parse_command:
255719261079SEd Maste len = strspn(str, WHITESPACE);
255819261079SEd Maste if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
255919261079SEd Maste fatal("%.200s line %d: %s must be an absolute path",
256019261079SEd Maste filename, linenum, keyword);
25616888a9beSDag-Erling Smørgrav }
2562535af610SEd Maste if (*activep && *charptr == NULL)
256319261079SEd Maste *charptr = xstrdup(str + len);
256419261079SEd Maste argv_consume(&ac);
256519261079SEd Maste break;
25666888a9beSDag-Erling Smørgrav
25676888a9beSDag-Erling Smørgrav case sAuthorizedKeysCommandUser:
25686888a9beSDag-Erling Smørgrav charptr = &options->authorized_keys_command_user;
256919261079SEd Maste parse_localuser:
257019261079SEd Maste arg = argv_next(&ac, &av);
257119261079SEd Maste if (!arg || *arg == '\0') {
257219261079SEd Maste fatal("%s line %d: missing %s argument.",
257319261079SEd Maste filename, linenum, keyword);
257419261079SEd Maste }
25756888a9beSDag-Erling Smørgrav if (*activep && *charptr == NULL)
25766888a9beSDag-Erling Smørgrav *charptr = xstrdup(arg);
25776888a9beSDag-Erling Smørgrav break;
25786888a9beSDag-Erling Smørgrav
2579557f75e5SDag-Erling Smørgrav case sAuthorizedPrincipalsCommand:
258019261079SEd Maste charptr = &options->authorized_principals_command;
258119261079SEd Maste goto parse_command;
2582557f75e5SDag-Erling Smørgrav
2583557f75e5SDag-Erling Smørgrav case sAuthorizedPrincipalsCommandUser:
2584557f75e5SDag-Erling Smørgrav charptr = &options->authorized_principals_command_user;
258519261079SEd Maste goto parse_localuser;
2586557f75e5SDag-Erling Smørgrav
25876888a9beSDag-Erling Smørgrav case sAuthenticationMethods:
258819261079SEd Maste found = options->num_auth_methods == 0;
2589076ad2f8SDag-Erling Smørgrav value = 0; /* seen "any" pseudo-method */
259019261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
2591076ad2f8SDag-Erling Smørgrav if (strcmp(arg, "any") == 0) {
2592a91a2465SEd Maste if (nstrs > 0) {
259319261079SEd Maste fatal("%s line %d: \"any\" must "
259419261079SEd Maste "appear alone in %s",
259519261079SEd Maste filename, linenum, keyword);
2596076ad2f8SDag-Erling Smørgrav }
2597076ad2f8SDag-Erling Smørgrav value = 1;
2598076ad2f8SDag-Erling Smørgrav } else if (value) {
2599076ad2f8SDag-Erling Smørgrav fatal("%s line %d: \"any\" must appear "
260019261079SEd Maste "alone in %s", filename, linenum, keyword);
2601076ad2f8SDag-Erling Smørgrav } else if (auth2_methods_valid(arg, 0) != 0) {
260219261079SEd Maste fatal("%s line %d: invalid %s method list.",
260319261079SEd Maste filename, linenum, keyword);
2604076ad2f8SDag-Erling Smørgrav }
260519261079SEd Maste opt_array_append(filename, linenum, keyword,
2606a91a2465SEd Maste &strs, &nstrs, arg);
26076888a9beSDag-Erling Smørgrav }
2608a91a2465SEd Maste if (nstrs == 0) {
260919261079SEd Maste fatal("%s line %d: no %s specified",
261019261079SEd Maste filename, linenum, keyword);
2611076ad2f8SDag-Erling Smørgrav }
2612a91a2465SEd Maste if (found && *activep) {
2613a91a2465SEd Maste options->auth_methods = strs;
2614a91a2465SEd Maste options->num_auth_methods = nstrs;
2615a91a2465SEd Maste strs = NULL; /* transferred */
2616a91a2465SEd Maste nstrs = 0;
2617a91a2465SEd Maste }
261819261079SEd Maste break;
26196888a9beSDag-Erling Smørgrav
2620a0ee8cc6SDag-Erling Smørgrav case sStreamLocalBindMask:
262119261079SEd Maste arg = argv_next(&ac, &av);
2622a0ee8cc6SDag-Erling Smørgrav if (!arg || *arg == '\0')
262319261079SEd Maste fatal("%s line %d: %s missing argument.",
262419261079SEd Maste filename, linenum, keyword);
2625a0ee8cc6SDag-Erling Smørgrav /* Parse mode in octal format */
2626a0ee8cc6SDag-Erling Smørgrav value = strtol(arg, &p, 8);
2627a0ee8cc6SDag-Erling Smørgrav if (arg == p || value < 0 || value > 0777)
262819261079SEd Maste fatal("%s line %d: Invalid %s.",
262919261079SEd Maste filename, linenum, keyword);
2630557f75e5SDag-Erling Smørgrav if (*activep)
2631a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2632a0ee8cc6SDag-Erling Smørgrav break;
2633a0ee8cc6SDag-Erling Smørgrav
2634a0ee8cc6SDag-Erling Smørgrav case sStreamLocalBindUnlink:
2635a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.streamlocal_bind_unlink;
2636a0ee8cc6SDag-Erling Smørgrav goto parse_flag;
2637a0ee8cc6SDag-Erling Smørgrav
2638bc5531deSDag-Erling Smørgrav case sFingerprintHash:
263919261079SEd Maste arg = argv_next(&ac, &av);
2640bc5531deSDag-Erling Smørgrav if (!arg || *arg == '\0')
264119261079SEd Maste fatal("%s line %d: %s missing argument.",
264219261079SEd Maste filename, linenum, keyword);
2643bc5531deSDag-Erling Smørgrav if ((value = ssh_digest_alg_by_name(arg)) == -1)
264419261079SEd Maste fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
264519261079SEd Maste filename, linenum, keyword, arg);
2646bc5531deSDag-Erling Smørgrav if (*activep)
2647bc5531deSDag-Erling Smørgrav options->fingerprint_hash = value;
2648bc5531deSDag-Erling Smørgrav break;
2649bc5531deSDag-Erling Smørgrav
26504f52dfbbSDag-Erling Smørgrav case sExposeAuthInfo:
26514f52dfbbSDag-Erling Smørgrav intptr = &options->expose_userauth_info;
26524f52dfbbSDag-Erling Smørgrav goto parse_flag;
26534f52dfbbSDag-Erling Smørgrav
265447dd1d1bSDag-Erling Smørgrav case sRDomain:
265519261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
265619261079SEd Maste fatal("%s line %d: setting RDomain not supported on this "
265719261079SEd Maste "platform.", filename, linenum);
265819261079SEd Maste #endif
265947dd1d1bSDag-Erling Smørgrav charptr = &options->routing_domain;
266019261079SEd Maste arg = argv_next(&ac, &av);
266147dd1d1bSDag-Erling Smørgrav if (!arg || *arg == '\0')
266219261079SEd Maste fatal("%s line %d: %s missing argument.",
266319261079SEd Maste filename, linenum, keyword);
266447dd1d1bSDag-Erling Smørgrav if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
266547dd1d1bSDag-Erling Smørgrav !valid_rdomain(arg))
266619261079SEd Maste fatal("%s line %d: invalid routing domain",
266747dd1d1bSDag-Erling Smørgrav filename, linenum);
266847dd1d1bSDag-Erling Smørgrav if (*activep && *charptr == NULL)
266947dd1d1bSDag-Erling Smørgrav *charptr = xstrdup(arg);
267047dd1d1bSDag-Erling Smørgrav break;
267147dd1d1bSDag-Erling Smørgrav
267238a52bd3SEd Maste case sRequiredRSASize:
267338a52bd3SEd Maste intptr = &options->required_rsa_size;
267438a52bd3SEd Maste goto parse_int;
267538a52bd3SEd Maste
2676f374ba41SEd Maste case sChannelTimeout:
2677a91a2465SEd Maste found = options->num_channel_timeouts == 0;
2678f374ba41SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
2679f374ba41SEd Maste /* Allow "none" only in first position */
2680f374ba41SEd Maste if (strcasecmp(arg, "none") == 0) {
2681a91a2465SEd Maste if (nstrs > 0 || ac > 0) {
2682f374ba41SEd Maste error("%s line %d: keyword %s \"none\" "
2683f374ba41SEd Maste "argument must appear alone.",
2684f374ba41SEd Maste filename, linenum, keyword);
2685f374ba41SEd Maste goto out;
2686f374ba41SEd Maste }
2687069ac184SEd Maste } else if (parse_pattern_interval(arg,
2688069ac184SEd Maste NULL, NULL) != 0) {
2689f374ba41SEd Maste fatal("%s line %d: invalid channel timeout %s",
2690f374ba41SEd Maste filename, linenum, arg);
2691f374ba41SEd Maste }
2692f374ba41SEd Maste opt_array_append(filename, linenum, keyword,
2693a91a2465SEd Maste &strs, &nstrs, arg);
2694a91a2465SEd Maste }
2695a91a2465SEd Maste if (nstrs == 0) {
2696a91a2465SEd Maste fatal("%s line %d: no %s specified",
2697a91a2465SEd Maste filename, linenum, keyword);
2698a91a2465SEd Maste }
2699a91a2465SEd Maste if (found && *activep) {
2700a91a2465SEd Maste options->channel_timeouts = strs;
2701a91a2465SEd Maste options->num_channel_timeouts = nstrs;
2702a91a2465SEd Maste strs = NULL; /* transferred */
2703a91a2465SEd Maste nstrs = 0;
2704f374ba41SEd Maste }
2705f374ba41SEd Maste break;
2706f374ba41SEd Maste
2707f374ba41SEd Maste case sUnusedConnectionTimeout:
2708f374ba41SEd Maste intptr = &options->unused_connection_timeout;
2709f374ba41SEd Maste /* peek at first arg for "none" so we can reuse parse_time */
2710f374ba41SEd Maste if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2711f374ba41SEd Maste (void)argv_next(&ac, &av); /* consume arg */
2712f374ba41SEd Maste if (*activep)
2713f374ba41SEd Maste *intptr = 0;
2714f374ba41SEd Maste break;
2715f374ba41SEd Maste }
2716f374ba41SEd Maste goto parse_time;
2717f374ba41SEd Maste
27180fdf8faeSEd Maste case sSshdSessionPath:
27190fdf8faeSEd Maste charptr = &options->sshd_session_path;
27200fdf8faeSEd Maste goto parse_filename;
27210fdf8faeSEd Maste
27223d9fd9fcSEd Maste case sRefuseConnection:
27233d9fd9fcSEd Maste intptr = &options->refuse_connection;
27243d9fd9fcSEd Maste multistate_ptr = multistate_flag;
27253d9fd9fcSEd Maste goto parse_multistate;
27263d9fd9fcSEd Maste
2727b2af61ecSKurt Lidl case sUseBlacklist:
2728b2af61ecSKurt Lidl intptr = &options->use_blacklist;
2729b2af61ecSKurt Lidl goto parse_flag;
2730b2af61ecSKurt Lidl
2731af12a3e7SDag-Erling Smørgrav case sDeprecated:
2732ca86bcf2SDag-Erling Smørgrav case sIgnore:
2733cf2b5f3bSDag-Erling Smørgrav case sUnsupported:
2734ca86bcf2SDag-Erling Smørgrav do_log2(opcode == sIgnore ?
2735ca86bcf2SDag-Erling Smørgrav SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2736ca86bcf2SDag-Erling Smørgrav "%s line %d: %s option %s", filename, linenum,
273719261079SEd Maste opcode == sUnsupported ? "Unsupported" : "Deprecated",
273819261079SEd Maste keyword);
273919261079SEd Maste argv_consume(&ac);
2740af12a3e7SDag-Erling Smørgrav break;
2741af12a3e7SDag-Erling Smørgrav
274242f71286SMark Murray default:
2743af12a3e7SDag-Erling Smørgrav fatal("%s line %d: Missing handler for opcode %s (%d)",
274419261079SEd Maste filename, linenum, keyword, opcode);
2745511b41d2SMark Murray }
274619261079SEd Maste /* Check that there is no garbage at end of line. */
274719261079SEd Maste if (ac > 0) {
274819261079SEd Maste error("%.200s line %d: keyword %s extra arguments "
274919261079SEd Maste "at end of line", filename, linenum, keyword);
275019261079SEd Maste goto out;
2751af12a3e7SDag-Erling Smørgrav }
2752af12a3e7SDag-Erling Smørgrav
275319261079SEd Maste /* success */
275419261079SEd Maste ret = 0;
275519261079SEd Maste out:
2756a91a2465SEd Maste opt_array_free2(strs, NULL, nstrs);
275719261079SEd Maste argv_free(oav, oac);
275819261079SEd Maste return ret;
275919261079SEd Maste }
276019261079SEd Maste
276119261079SEd Maste int
process_server_config_line(ServerOptions * options,char * line,const char * filename,int linenum,int * activep,struct connection_info * connectinfo,struct include_list * includes)276219261079SEd Maste process_server_config_line(ServerOptions *options, char *line,
276319261079SEd Maste const char *filename, int linenum, int *activep,
276419261079SEd Maste struct connection_info *connectinfo, struct include_list *includes)
276519261079SEd Maste {
276619261079SEd Maste int inc_flags = 0;
276719261079SEd Maste
276819261079SEd Maste return process_server_config_line_depth(options, line, filename,
276919261079SEd Maste linenum, activep, connectinfo, &inc_flags, 0, includes);
277019261079SEd Maste }
277119261079SEd Maste
277219261079SEd Maste
2773af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */
2774af12a3e7SDag-Erling Smørgrav
2775af12a3e7SDag-Erling Smørgrav void
load_server_config(const char * filename,struct sshbuf * conf)2776190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf)
2777af12a3e7SDag-Erling Smørgrav {
277819261079SEd Maste struct stat st;
2779190cef3dSDag-Erling Smørgrav char *line = NULL, *cp;
2780190cef3dSDag-Erling Smørgrav size_t linesize = 0;
2781a82e551fSDag-Erling Smørgrav FILE *f;
2782f374ba41SEd Maste int r;
2783af12a3e7SDag-Erling Smørgrav
278419261079SEd Maste debug2_f("filename %s", filename);
278521e764dfSDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) {
2786af12a3e7SDag-Erling Smørgrav perror(filename);
2787af12a3e7SDag-Erling Smørgrav exit(1);
2788af12a3e7SDag-Erling Smørgrav }
2789190cef3dSDag-Erling Smørgrav sshbuf_reset(conf);
279019261079SEd Maste /* grow buffer, so realloc is avoided for large config files */
279119261079SEd Maste if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
279219261079SEd Maste (r = sshbuf_allocate(conf, st.st_size)) != 0)
279319261079SEd Maste fatal_fr(r, "allocate");
2794190cef3dSDag-Erling Smørgrav while (getline(&line, &linesize, f) != -1) {
279521e764dfSDag-Erling Smørgrav /*
279619261079SEd Maste * Strip whitespace
279721e764dfSDag-Erling Smørgrav * NB - preserve newlines, they are needed to reproduce
279821e764dfSDag-Erling Smørgrav * line numbers later for error messages
279921e764dfSDag-Erling Smørgrav */
280021e764dfSDag-Erling Smørgrav cp = line + strspn(line, " \t\r");
2801190cef3dSDag-Erling Smørgrav if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
280219261079SEd Maste fatal_fr(r, "sshbuf_put");
280321e764dfSDag-Erling Smørgrav }
2804190cef3dSDag-Erling Smørgrav free(line);
2805190cef3dSDag-Erling Smørgrav if ((r = sshbuf_put_u8(conf, 0)) != 0)
280619261079SEd Maste fatal_fr(r, "sshbuf_put_u8");
280721e764dfSDag-Erling Smørgrav fclose(f);
280819261079SEd Maste debug2_f("done config len = %zu", sshbuf_len(conf));
280921e764dfSDag-Erling Smørgrav }
281021e764dfSDag-Erling Smørgrav
281121e764dfSDag-Erling Smørgrav void
parse_server_match_config(ServerOptions * options,struct include_list * includes,struct connection_info * connectinfo)2812462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options,
281319261079SEd Maste struct include_list *includes, struct connection_info *connectinfo)
281421e764dfSDag-Erling Smørgrav {
2815333ee039SDag-Erling Smørgrav ServerOptions mo;
2816333ee039SDag-Erling Smørgrav
2817333ee039SDag-Erling Smørgrav initialize_server_options(&mo);
281819261079SEd Maste parse_server_config(&mo, "reprocess config", cfg, includes,
281987c1498dSEd Maste connectinfo, 0);
2820d4af9e69SDag-Erling Smørgrav copy_set_server_options(options, &mo, 0);
2821333ee039SDag-Erling Smørgrav }
2822333ee039SDag-Erling Smørgrav
parse_server_match_testspec(struct connection_info * ci,char * spec)2823462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec)
2824462c32cbSDag-Erling Smørgrav {
2825462c32cbSDag-Erling Smørgrav char *p;
2826462c32cbSDag-Erling Smørgrav
2827462c32cbSDag-Erling Smørgrav while ((p = strsep(&spec, ",")) && *p != '\0') {
2828462c32cbSDag-Erling Smørgrav if (strncmp(p, "addr=", 5) == 0) {
2829462c32cbSDag-Erling Smørgrav ci->address = xstrdup(p + 5);
2830462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "host=", 5) == 0) {
2831462c32cbSDag-Erling Smørgrav ci->host = xstrdup(p + 5);
2832462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "user=", 5) == 0) {
2833462c32cbSDag-Erling Smørgrav ci->user = xstrdup(p + 5);
2834462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "laddr=", 6) == 0) {
2835462c32cbSDag-Erling Smørgrav ci->laddress = xstrdup(p + 6);
283647dd1d1bSDag-Erling Smørgrav } else if (strncmp(p, "rdomain=", 8) == 0) {
283747dd1d1bSDag-Erling Smørgrav ci->rdomain = xstrdup(p + 8);
2838462c32cbSDag-Erling Smørgrav } else if (strncmp(p, "lport=", 6) == 0) {
2839462c32cbSDag-Erling Smørgrav ci->lport = a2port(p + 6);
2840462c32cbSDag-Erling Smørgrav if (ci->lport == -1) {
2841462c32cbSDag-Erling Smørgrav fprintf(stderr, "Invalid port '%s' in test mode"
2842462c32cbSDag-Erling Smørgrav " specification %s\n", p+6, p);
2843462c32cbSDag-Erling Smørgrav return -1;
2844462c32cbSDag-Erling Smørgrav }
28453d9fd9fcSEd Maste } else if (strcmp(p, "invalid-user") == 0) {
28463d9fd9fcSEd Maste ci->user_invalid = 1;
2847462c32cbSDag-Erling Smørgrav } else {
2848462c32cbSDag-Erling Smørgrav fprintf(stderr, "Invalid test mode specification %s\n",
2849462c32cbSDag-Erling Smørgrav p);
2850462c32cbSDag-Erling Smørgrav return -1;
2851462c32cbSDag-Erling Smørgrav }
2852462c32cbSDag-Erling Smørgrav }
2853462c32cbSDag-Erling Smørgrav return 0;
2854462c32cbSDag-Erling Smørgrav }
2855462c32cbSDag-Erling Smørgrav
2856edf85781SEd Maste void
servconf_merge_subsystems(ServerOptions * dst,ServerOptions * src)2857edf85781SEd Maste servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
2858edf85781SEd Maste {
2859edf85781SEd Maste u_int i, j, found;
2860edf85781SEd Maste
2861edf85781SEd Maste for (i = 0; i < src->num_subsystems; i++) {
2862edf85781SEd Maste found = 0;
2863edf85781SEd Maste for (j = 0; j < dst->num_subsystems; j++) {
2864edf85781SEd Maste if (strcmp(src->subsystem_name[i],
2865edf85781SEd Maste dst->subsystem_name[j]) == 0) {
2866edf85781SEd Maste found = 1;
2867edf85781SEd Maste break;
2868edf85781SEd Maste }
2869edf85781SEd Maste }
2870edf85781SEd Maste if (found) {
2871edf85781SEd Maste debug_f("override \"%s\"", dst->subsystem_name[j]);
2872edf85781SEd Maste free(dst->subsystem_command[j]);
2873edf85781SEd Maste free(dst->subsystem_args[j]);
2874edf85781SEd Maste dst->subsystem_command[j] =
2875edf85781SEd Maste xstrdup(src->subsystem_command[i]);
2876edf85781SEd Maste dst->subsystem_args[j] =
2877edf85781SEd Maste xstrdup(src->subsystem_args[i]);
2878edf85781SEd Maste continue;
2879edf85781SEd Maste }
2880edf85781SEd Maste debug_f("add \"%s\"", src->subsystem_name[i]);
2881edf85781SEd Maste dst->subsystem_name = xrecallocarray(
2882edf85781SEd Maste dst->subsystem_name, dst->num_subsystems,
2883edf85781SEd Maste dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
2884edf85781SEd Maste dst->subsystem_command = xrecallocarray(
2885edf85781SEd Maste dst->subsystem_command, dst->num_subsystems,
2886edf85781SEd Maste dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
2887edf85781SEd Maste dst->subsystem_args = xrecallocarray(
2888edf85781SEd Maste dst->subsystem_args, dst->num_subsystems,
2889edf85781SEd Maste dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
2890edf85781SEd Maste j = dst->num_subsystems++;
2891edf85781SEd Maste dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
2892edf85781SEd Maste dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
2893edf85781SEd Maste dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
2894edf85781SEd Maste }
2895edf85781SEd Maste }
2896edf85781SEd Maste
2897462c32cbSDag-Erling Smørgrav /*
2898d4af9e69SDag-Erling Smørgrav * Copy any supported values that are set.
2899d4af9e69SDag-Erling Smørgrav *
29007aee6ffeSDag-Erling Smørgrav * If the preauth flag is set, we do not bother copying the string or
2901d4af9e69SDag-Erling Smørgrav * array values that are not used pre-authentication, because any that we
2902190cef3dSDag-Erling Smørgrav * do use must be explicitly sent in mm_getpwnamallow().
2903d4af9e69SDag-Erling Smørgrav */
2904333ee039SDag-Erling Smørgrav void
copy_set_server_options(ServerOptions * dst,ServerOptions * src,int preauth)2905d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2906333ee039SDag-Erling Smørgrav {
2907f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\
2908f7167e0eSDag-Erling Smørgrav if (src->n != -1) \
2909f7167e0eSDag-Erling Smørgrav dst->n = src->n; \
2910f7167e0eSDag-Erling Smørgrav } while (0)
2911f7167e0eSDag-Erling Smørgrav
2912d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(password_authentication);
2913d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(gss_authentication);
2914d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(pubkey_authentication);
291519261079SEd Maste M_CP_INTOPT(pubkey_auth_options);
2916d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(kerberos_authentication);
2917d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(hostbased_authentication);
2918e2f6069cSDag-Erling Smørgrav M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2919d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(kbd_interactive_authentication);
2920d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(permit_root_login);
2921cce7d346SDag-Erling Smørgrav M_CP_INTOPT(permit_empty_passwd);
292219261079SEd Maste M_CP_INTOPT(ignore_rhosts);
2923d4af9e69SDag-Erling Smørgrav
2924d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(allow_tcp_forwarding);
2925a0ee8cc6SDag-Erling Smørgrav M_CP_INTOPT(allow_streamlocal_forwarding);
2926d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(allow_agent_forwarding);
2927ca86bcf2SDag-Erling Smørgrav M_CP_INTOPT(disable_forwarding);
29284f52dfbbSDag-Erling Smørgrav M_CP_INTOPT(expose_userauth_info);
2929e2f6069cSDag-Erling Smørgrav M_CP_INTOPT(permit_tun);
2930a0ee8cc6SDag-Erling Smørgrav M_CP_INTOPT(fwd_opts.gateway_ports);
2931076ad2f8SDag-Erling Smørgrav M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2932d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(x11_display_offset);
2933d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(x11_forwarding);
2934d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(x11_use_localhost);
2935f7167e0eSDag-Erling Smørgrav M_CP_INTOPT(permit_tty);
2936a0ee8cc6SDag-Erling Smørgrav M_CP_INTOPT(permit_user_rc);
2937d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(max_sessions);
2938d4af9e69SDag-Erling Smørgrav M_CP_INTOPT(max_authtries);
2939ca86bcf2SDag-Erling Smørgrav M_CP_INTOPT(client_alive_count_max);
2940ca86bcf2SDag-Erling Smørgrav M_CP_INTOPT(client_alive_interval);
29414a421b63SDag-Erling Smørgrav M_CP_INTOPT(ip_qos_interactive);
29424a421b63SDag-Erling Smørgrav M_CP_INTOPT(ip_qos_bulk);
2943e4a9863fSDag-Erling Smørgrav M_CP_INTOPT(rekey_limit);
2944e4a9863fSDag-Erling Smørgrav M_CP_INTOPT(rekey_interval);
29454f52dfbbSDag-Erling Smørgrav M_CP_INTOPT(log_level);
294638a52bd3SEd Maste M_CP_INTOPT(required_rsa_size);
2947f374ba41SEd Maste M_CP_INTOPT(unused_connection_timeout);
29483d9fd9fcSEd Maste M_CP_INTOPT(refuse_connection);
2949d4af9e69SDag-Erling Smørgrav
2950076ad2f8SDag-Erling Smørgrav /*
2951076ad2f8SDag-Erling Smørgrav * The bind_mask is a mode_t that may be unsigned, so we can't use
2952076ad2f8SDag-Erling Smørgrav * M_CP_INTOPT - it does a signed comparison that causes compiler
2953076ad2f8SDag-Erling Smørgrav * warnings.
2954076ad2f8SDag-Erling Smørgrav */
2955076ad2f8SDag-Erling Smørgrav if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2956076ad2f8SDag-Erling Smørgrav dst->fwd_opts.streamlocal_bind_mask =
2957076ad2f8SDag-Erling Smørgrav src->fwd_opts.streamlocal_bind_mask;
2958076ad2f8SDag-Erling Smørgrav }
2959076ad2f8SDag-Erling Smørgrav
2960f7167e0eSDag-Erling Smørgrav /* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2961f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\
2962f7167e0eSDag-Erling Smørgrav if (src->n != NULL && dst->n != src->n) { \
2963f7167e0eSDag-Erling Smørgrav free(dst->n); \
2964f7167e0eSDag-Erling Smørgrav dst->n = src->n; \
2965f7167e0eSDag-Erling Smørgrav } \
2966f7167e0eSDag-Erling Smørgrav } while(0)
296747dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\
296847dd1d1bSDag-Erling Smørgrav u_int i; \
296947dd1d1bSDag-Erling Smørgrav if (src->num_s != 0) { \
297047dd1d1bSDag-Erling Smørgrav for (i = 0; i < dst->num_s; i++) \
297147dd1d1bSDag-Erling Smørgrav free(dst->s[i]); \
297247dd1d1bSDag-Erling Smørgrav free(dst->s); \
297347dd1d1bSDag-Erling Smørgrav dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
297447dd1d1bSDag-Erling Smørgrav for (i = 0; i < src->num_s; i++) \
297547dd1d1bSDag-Erling Smørgrav dst->s[i] = xstrdup(src->s[i]); \
297647dd1d1bSDag-Erling Smørgrav dst->num_s = src->num_s; \
29774f52dfbbSDag-Erling Smørgrav } \
29784f52dfbbSDag-Erling Smørgrav } while(0)
2979f7167e0eSDag-Erling Smørgrav
2980e146993eSDag-Erling Smørgrav /* See comment in servconf.h */
2981e146993eSDag-Erling Smørgrav COPY_MATCH_STRING_OPTS();
2982e146993eSDag-Erling Smørgrav
2983acc1a9efSDag-Erling Smørgrav /* Arguments that accept '+...' need to be expanded */
2984acc1a9efSDag-Erling Smørgrav assemble_algorithms(dst);
2985acc1a9efSDag-Erling Smørgrav
2986e146993eSDag-Erling Smørgrav /*
2987e146993eSDag-Erling Smørgrav * The only things that should be below this point are string options
2988e146993eSDag-Erling Smørgrav * which are only used after authentication.
2989e146993eSDag-Erling Smørgrav */
2990d4af9e69SDag-Erling Smørgrav if (preauth)
2991d4af9e69SDag-Erling Smørgrav return;
2992e146993eSDag-Erling Smørgrav
2993acc1a9efSDag-Erling Smørgrav /* These options may be "none" to clear a global setting */
2994d4af9e69SDag-Erling Smørgrav M_CP_STROPT(adm_forced_command);
2995acc1a9efSDag-Erling Smørgrav if (option_clear_or_none(dst->adm_forced_command)) {
2996acc1a9efSDag-Erling Smørgrav free(dst->adm_forced_command);
2997acc1a9efSDag-Erling Smørgrav dst->adm_forced_command = NULL;
2998acc1a9efSDag-Erling Smørgrav }
2999d4af9e69SDag-Erling Smørgrav M_CP_STROPT(chroot_directory);
3000acc1a9efSDag-Erling Smørgrav if (option_clear_or_none(dst->chroot_directory)) {
3001acc1a9efSDag-Erling Smørgrav free(dst->chroot_directory);
3002acc1a9efSDag-Erling Smørgrav dst->chroot_directory = NULL;
3003acc1a9efSDag-Erling Smørgrav }
3004edf85781SEd Maste
3005edf85781SEd Maste /* Subsystems require merging. */
3006edf85781SEd Maste servconf_merge_subsystems(dst, src);
3007333ee039SDag-Erling Smørgrav }
3008d4af9e69SDag-Erling Smørgrav
3009d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT
3010d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT
3011e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT
3012333ee039SDag-Erling Smørgrav
301319261079SEd Maste #define SERVCONF_MAX_DEPTH 16
301419261079SEd Maste static void
parse_server_config_depth(ServerOptions * options,const char * filename,struct sshbuf * conf,struct include_list * includes,struct connection_info * connectinfo,int flags,int * activep,int depth)301519261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename,
301619261079SEd Maste struct sshbuf *conf, struct include_list *includes,
301719261079SEd Maste struct connection_info *connectinfo, int flags, int *activep, int depth)
3018333ee039SDag-Erling Smørgrav {
301919261079SEd Maste int linenum, bad_options = 0;
302021e764dfSDag-Erling Smørgrav char *cp, *obuf, *cbuf;
302121e764dfSDag-Erling Smørgrav
302219261079SEd Maste if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
302319261079SEd Maste fatal("Too many recursive configuration includes");
302419261079SEd Maste
302519261079SEd Maste debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
302619261079SEd Maste (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
302721e764dfSDag-Erling Smørgrav
3028076ad2f8SDag-Erling Smørgrav if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
302919261079SEd Maste fatal_f("sshbuf_dup_string failed");
303021e764dfSDag-Erling Smørgrav linenum = 1;
303121e764dfSDag-Erling Smørgrav while ((cp = strsep(&cbuf, "\n")) != NULL) {
303219261079SEd Maste if (process_server_config_line_depth(options, cp,
303319261079SEd Maste filename, linenum++, activep, connectinfo, &flags,
303419261079SEd Maste depth, includes) != 0)
3035af12a3e7SDag-Erling Smørgrav bad_options++;
3036511b41d2SMark Murray }
3037e4a9863fSDag-Erling Smørgrav free(obuf);
3038ca3176e7SBrian Feldman if (bad_options > 0)
3039af12a3e7SDag-Erling Smørgrav fatal("%s: terminating, %d bad configuration options",
3040511b41d2SMark Murray filename, bad_options);
304119261079SEd Maste }
304219261079SEd Maste
304319261079SEd Maste void
parse_server_config(ServerOptions * options,const char * filename,struct sshbuf * conf,struct include_list * includes,struct connection_info * connectinfo,int reexec)304419261079SEd Maste parse_server_config(ServerOptions *options, const char *filename,
304519261079SEd Maste struct sshbuf *conf, struct include_list *includes,
304687c1498dSEd Maste struct connection_info *connectinfo, int reexec)
304719261079SEd Maste {
304819261079SEd Maste int active = connectinfo ? 0 : 1;
304919261079SEd Maste parse_server_config_depth(options, filename, conf, includes,
305019261079SEd Maste connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
305187c1498dSEd Maste if (!reexec)
3052557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(options);
3053511b41d2SMark Murray }
3054d4af9e69SDag-Erling Smørgrav
3055d4af9e69SDag-Erling Smørgrav static const char *
fmt_multistate_int(int val,const struct multistate * m)3056e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
3057d4af9e69SDag-Erling Smørgrav {
3058e146993eSDag-Erling Smørgrav u_int i;
3059e146993eSDag-Erling Smørgrav
3060e146993eSDag-Erling Smørgrav for (i = 0; m[i].key != NULL; i++) {
3061e146993eSDag-Erling Smørgrav if (m[i].value == val)
3062e146993eSDag-Erling Smørgrav return m[i].key;
3063e146993eSDag-Erling Smørgrav }
3064d4af9e69SDag-Erling Smørgrav return "UNKNOWN";
3065d4af9e69SDag-Erling Smørgrav }
3066e146993eSDag-Erling Smørgrav
3067e146993eSDag-Erling Smørgrav static const char *
fmt_intarg(ServerOpCodes code,int val)3068e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val)
3069e146993eSDag-Erling Smørgrav {
3070e146993eSDag-Erling Smørgrav if (val == -1)
3071e146993eSDag-Erling Smørgrav return "unset";
3072e146993eSDag-Erling Smørgrav switch (code) {
3073e146993eSDag-Erling Smørgrav case sAddressFamily:
3074e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_addressfamily);
3075e146993eSDag-Erling Smørgrav case sPermitRootLogin:
3076e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_permitrootlogin);
3077e146993eSDag-Erling Smørgrav case sGatewayPorts:
3078e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_gatewayports);
3079e146993eSDag-Erling Smørgrav case sCompression:
3080e146993eSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_compression);
30816888a9beSDag-Erling Smørgrav case sAllowTcpForwarding:
30826888a9beSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tcpfwd);
3083a0ee8cc6SDag-Erling Smørgrav case sAllowStreamLocalForwarding:
3084a0ee8cc6SDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tcpfwd);
308519261079SEd Maste case sIgnoreRhosts:
308619261079SEd Maste return fmt_multistate_int(val, multistate_ignore_rhosts);
3087bc5531deSDag-Erling Smørgrav case sFingerprintHash:
3088bc5531deSDag-Erling Smørgrav return ssh_digest_alg_name(val);
3089e146993eSDag-Erling Smørgrav default:
3090d4af9e69SDag-Erling Smørgrav switch (val) {
3091d4af9e69SDag-Erling Smørgrav case 0:
3092d4af9e69SDag-Erling Smørgrav return "no";
3093d4af9e69SDag-Erling Smørgrav case 1:
3094d4af9e69SDag-Erling Smørgrav return "yes";
3095e146993eSDag-Erling Smørgrav default:
3096d4af9e69SDag-Erling Smørgrav return "UNKNOWN";
3097d4af9e69SDag-Erling Smørgrav }
3098e146993eSDag-Erling Smørgrav }
3099e146993eSDag-Erling Smørgrav }
3100d4af9e69SDag-Erling Smørgrav
3101d4af9e69SDag-Erling Smørgrav static void
dump_cfg_int(ServerOpCodes code,int val)3102d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val)
3103d4af9e69SDag-Erling Smørgrav {
3104f374ba41SEd Maste if (code == sUnusedConnectionTimeout && val == 0) {
3105f374ba41SEd Maste printf("%s none\n", lookup_opcode_name(code));
3106f374ba41SEd Maste return;
3107f374ba41SEd Maste }
3108d4af9e69SDag-Erling Smørgrav printf("%s %d\n", lookup_opcode_name(code), val);
3109d4af9e69SDag-Erling Smørgrav }
3110d4af9e69SDag-Erling Smørgrav
3111d4af9e69SDag-Erling Smørgrav static void
dump_cfg_oct(ServerOpCodes code,int val)3112557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val)
3113557f75e5SDag-Erling Smørgrav {
3114557f75e5SDag-Erling Smørgrav printf("%s 0%o\n", lookup_opcode_name(code), val);
3115557f75e5SDag-Erling Smørgrav }
3116557f75e5SDag-Erling Smørgrav
3117557f75e5SDag-Erling Smørgrav static void
dump_cfg_fmtint(ServerOpCodes code,int val)3118d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val)
3119d4af9e69SDag-Erling Smørgrav {
3120d4af9e69SDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3121d4af9e69SDag-Erling Smørgrav }
3122d4af9e69SDag-Erling Smørgrav
3123d4af9e69SDag-Erling Smørgrav static void
dump_cfg_string(ServerOpCodes code,const char * val)3124d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val)
3125d4af9e69SDag-Erling Smørgrav {
3126bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code),
3127bc5531deSDag-Erling Smørgrav val == NULL ? "none" : val);
3128d4af9e69SDag-Erling Smørgrav }
3129d4af9e69SDag-Erling Smørgrav
3130d4af9e69SDag-Erling Smørgrav static void
dump_cfg_strarray(ServerOpCodes code,u_int count,char ** vals)3131d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
3132d4af9e69SDag-Erling Smørgrav {
3133d4af9e69SDag-Erling Smørgrav u_int i;
3134d4af9e69SDag-Erling Smørgrav
3135d4af9e69SDag-Erling Smørgrav for (i = 0; i < count; i++)
3136d4af9e69SDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3137d4af9e69SDag-Erling Smørgrav }
3138d4af9e69SDag-Erling Smørgrav
3139e146993eSDag-Erling Smørgrav static void
dump_cfg_strarray_oneline(ServerOpCodes code,u_int count,char ** vals)3140e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
3141e146993eSDag-Erling Smørgrav {
3142e146993eSDag-Erling Smørgrav u_int i;
3143e146993eSDag-Erling Smørgrav
31444d3fc8b0SEd Maste switch (code) {
31454d3fc8b0SEd Maste case sAuthenticationMethods:
31464d3fc8b0SEd Maste case sChannelTimeout:
31474d3fc8b0SEd Maste break;
31484d3fc8b0SEd Maste default:
31494d3fc8b0SEd Maste if (count <= 0)
3150557f75e5SDag-Erling Smørgrav return;
31514d3fc8b0SEd Maste break;
31524d3fc8b0SEd Maste }
31534d3fc8b0SEd Maste
3154e146993eSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code));
3155e146993eSDag-Erling Smørgrav for (i = 0; i < count; i++)
3156e146993eSDag-Erling Smørgrav printf(" %s", vals[i]);
3157076ad2f8SDag-Erling Smørgrav if (code == sAuthenticationMethods && count == 0)
3158076ad2f8SDag-Erling Smørgrav printf(" any");
3159f374ba41SEd Maste else if (code == sChannelTimeout && count == 0)
3160f374ba41SEd Maste printf(" none");
3161e146993eSDag-Erling Smørgrav printf("\n");
3162e146993eSDag-Erling Smørgrav }
3163e146993eSDag-Erling Smørgrav
316447dd1d1bSDag-Erling Smørgrav static char *
format_listen_addrs(struct listenaddr * la)316547dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la)
3166d4af9e69SDag-Erling Smørgrav {
316747dd1d1bSDag-Erling Smørgrav int r;
3168d4af9e69SDag-Erling Smørgrav struct addrinfo *ai;
316947dd1d1bSDag-Erling Smørgrav char addr[NI_MAXHOST], port[NI_MAXSERV];
3170557f75e5SDag-Erling Smørgrav char *laddr1 = xstrdup(""), *laddr2 = NULL;
3171d4af9e69SDag-Erling Smørgrav
3172557f75e5SDag-Erling Smørgrav /*
3173557f75e5SDag-Erling Smørgrav * ListenAddress must be after Port. add_one_listen_addr pushes
3174557f75e5SDag-Erling Smørgrav * addresses onto a stack, so to maintain ordering we need to
3175557f75e5SDag-Erling Smørgrav * print these in reverse order.
3176557f75e5SDag-Erling Smørgrav */
317747dd1d1bSDag-Erling Smørgrav for (ai = la->addrs; ai; ai = ai->ai_next) {
317847dd1d1bSDag-Erling Smørgrav if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
3179d4af9e69SDag-Erling Smørgrav sizeof(addr), port, sizeof(port),
3180d4af9e69SDag-Erling Smørgrav NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
318147dd1d1bSDag-Erling Smørgrav error("getnameinfo: %.100s", ssh_gai_strerror(r));
318247dd1d1bSDag-Erling Smørgrav continue;
318347dd1d1bSDag-Erling Smørgrav }
3184557f75e5SDag-Erling Smørgrav laddr2 = laddr1;
318547dd1d1bSDag-Erling Smørgrav if (ai->ai_family == AF_INET6) {
318647dd1d1bSDag-Erling Smørgrav xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
318747dd1d1bSDag-Erling Smørgrav addr, port,
318847dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : " rdomain ",
318947dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : la->rdomain,
319047dd1d1bSDag-Erling Smørgrav laddr2);
319147dd1d1bSDag-Erling Smørgrav } else {
319247dd1d1bSDag-Erling Smørgrav xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
319347dd1d1bSDag-Erling Smørgrav addr, port,
319447dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : " rdomain ",
319547dd1d1bSDag-Erling Smørgrav la->rdomain == NULL ? "" : la->rdomain,
319647dd1d1bSDag-Erling Smørgrav laddr2);
319747dd1d1bSDag-Erling Smørgrav }
3198557f75e5SDag-Erling Smørgrav free(laddr2);
3199d4af9e69SDag-Erling Smørgrav }
320047dd1d1bSDag-Erling Smørgrav return laddr1;
3201d4af9e69SDag-Erling Smørgrav }
320247dd1d1bSDag-Erling Smørgrav
320347dd1d1bSDag-Erling Smørgrav void
dump_config(ServerOptions * o)320447dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o)
320547dd1d1bSDag-Erling Smørgrav {
320647dd1d1bSDag-Erling Smørgrav char *s;
320747dd1d1bSDag-Erling Smørgrav u_int i;
320847dd1d1bSDag-Erling Smørgrav
320947dd1d1bSDag-Erling Smørgrav /* these are usually at the top of the config */
321047dd1d1bSDag-Erling Smørgrav for (i = 0; i < o->num_ports; i++)
321147dd1d1bSDag-Erling Smørgrav printf("port %d\n", o->ports[i]);
321247dd1d1bSDag-Erling Smørgrav dump_cfg_fmtint(sAddressFamily, o->address_family);
321347dd1d1bSDag-Erling Smørgrav
321447dd1d1bSDag-Erling Smørgrav for (i = 0; i < o->num_listen_addrs; i++) {
321547dd1d1bSDag-Erling Smørgrav s = format_listen_addrs(&o->listen_addrs[i]);
321647dd1d1bSDag-Erling Smørgrav printf("%s", s);
321747dd1d1bSDag-Erling Smørgrav free(s);
321847dd1d1bSDag-Erling Smørgrav }
3219d4af9e69SDag-Erling Smørgrav
3220d4af9e69SDag-Erling Smørgrav /* integer arguments */
3221cce7d346SDag-Erling Smørgrav #ifdef USE_PAM
3222557f75e5SDag-Erling Smørgrav dump_cfg_fmtint(sUsePAM, o->use_pam);
32230fdf8faeSEd Maste dump_cfg_string(sPAMServiceName, o->pam_service_name);
3224cce7d346SDag-Erling Smørgrav #endif
3225d4af9e69SDag-Erling Smørgrav dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3226d4af9e69SDag-Erling Smørgrav dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3227d4af9e69SDag-Erling Smørgrav dump_cfg_int(sMaxAuthTries, o->max_authtries);
3228cce7d346SDag-Erling Smørgrav dump_cfg_int(sMaxSessions, o->max_sessions);
3229d4af9e69SDag-Erling Smørgrav dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3230d4af9e69SDag-Erling Smørgrav dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
323138a52bd3SEd Maste dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3232557f75e5SDag-Erling Smørgrav dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3233f374ba41SEd Maste dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3234d4af9e69SDag-Erling Smørgrav
3235d4af9e69SDag-Erling Smørgrav /* formatted integer arguments */
3236d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3237d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3238d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3239d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3240d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3241d4af9e69SDag-Erling Smørgrav o->hostbased_uses_name_from_packet_only);
3242d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3243cce7d346SDag-Erling Smørgrav #ifdef KRB5
3244d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3245d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3246d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3247cce7d346SDag-Erling Smørgrav # ifdef USE_AFS
3248d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3249cce7d346SDag-Erling Smørgrav # endif
3250cce7d346SDag-Erling Smørgrav #endif
3251cce7d346SDag-Erling Smørgrav #ifdef GSSAPI
3252d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3253d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3254cce7d346SDag-Erling Smørgrav #endif
3255d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3256d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sKbdInteractiveAuthentication,
3257d4af9e69SDag-Erling Smørgrav o->kbd_interactive_authentication);
3258d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPrintMotd, o->print_motd);
3259acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG
3260d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3261acc1a9efSDag-Erling Smørgrav #endif
3262d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3263d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3264f7167e0eSDag-Erling Smørgrav dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3265a0ee8cc6SDag-Erling Smørgrav dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3266d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sStrictModes, o->strict_modes);
3267d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3268d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3269d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sCompression, o->compression);
3270a0ee8cc6SDag-Erling Smørgrav dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3271d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sUseDNS, o->use_dns);
3272d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3273557f75e5SDag-Erling Smørgrav dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3274ca86bcf2SDag-Erling Smørgrav dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3275a0ee8cc6SDag-Erling Smørgrav dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3276076ad2f8SDag-Erling Smørgrav dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3277bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
32784f52dfbbSDag-Erling Smørgrav dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
32793d9fd9fcSEd Maste dump_cfg_fmtint(sRefuseConnection, o->refuse_connection);
3280b2af61ecSKurt Lidl dump_cfg_fmtint(sUseBlacklist, o->use_blacklist);
3281d4af9e69SDag-Erling Smørgrav
3282d4af9e69SDag-Erling Smørgrav /* string arguments */
3283d4af9e69SDag-Erling Smørgrav dump_cfg_string(sPidFile, o->pid_file);
328419261079SEd Maste dump_cfg_string(sModuliFile, o->moduli_file);
3285d4af9e69SDag-Erling Smørgrav dump_cfg_string(sXAuthLocation, o->xauth_location);
328619261079SEd Maste dump_cfg_string(sCiphers, o->ciphers);
328719261079SEd Maste dump_cfg_string(sMacs, o->macs);
3288d4af9e69SDag-Erling Smørgrav dump_cfg_string(sBanner, o->banner);
3289d4af9e69SDag-Erling Smørgrav dump_cfg_string(sForceCommand, o->adm_forced_command);
3290b15c8340SDag-Erling Smørgrav dump_cfg_string(sChrootDirectory, o->chroot_directory);
3291b15c8340SDag-Erling Smørgrav dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3292b15c8340SDag-Erling Smørgrav dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
329319261079SEd Maste dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3294e2f6069cSDag-Erling Smørgrav dump_cfg_string(sAuthorizedPrincipalsFile,
3295e2f6069cSDag-Erling Smørgrav o->authorized_principals_file);
3296557f75e5SDag-Erling Smørgrav dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3297557f75e5SDag-Erling Smørgrav ? "none" : o->version_addendum);
32986888a9beSDag-Erling Smørgrav dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
32996888a9beSDag-Erling Smørgrav dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3300557f75e5SDag-Erling Smørgrav dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3301557f75e5SDag-Erling Smørgrav dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3302e4a9863fSDag-Erling Smørgrav dump_cfg_string(sHostKeyAgent, o->host_key_agent);
330319261079SEd Maste dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
330419261079SEd Maste dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
330519261079SEd Maste dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
330619261079SEd Maste dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
330719261079SEd Maste dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
330819261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
330947dd1d1bSDag-Erling Smørgrav dump_cfg_string(sRDomain, o->routing_domain);
331019261079SEd Maste #endif
33110fdf8faeSEd Maste dump_cfg_string(sSshdSessionPath, o->sshd_session_path);
33120fdf8faeSEd Maste dump_cfg_string(sPerSourcePenaltyExemptList, o->per_source_penalty_exempt);
3313d4af9e69SDag-Erling Smørgrav
3314d4af9e69SDag-Erling Smørgrav /* string arguments requiring a lookup */
3315d4af9e69SDag-Erling Smørgrav dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3316d4af9e69SDag-Erling Smørgrav dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3317d4af9e69SDag-Erling Smørgrav
3318d4af9e69SDag-Erling Smørgrav /* string array arguments */
3319e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3320e146993eSDag-Erling Smørgrav o->authorized_keys_files);
3321d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3322d4af9e69SDag-Erling Smørgrav o->host_key_files);
3323557f75e5SDag-Erling Smørgrav dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3324b15c8340SDag-Erling Smørgrav o->host_cert_files);
3325d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3326d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3327d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3328d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3329d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3330190cef3dSDag-Erling Smørgrav dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
33316888a9beSDag-Erling Smørgrav dump_cfg_strarray_oneline(sAuthenticationMethods,
33326888a9beSDag-Erling Smørgrav o->num_auth_methods, o->auth_methods);
333319261079SEd Maste dump_cfg_strarray_oneline(sLogVerbose,
333419261079SEd Maste o->num_log_verbose, o->log_verbose);
3335f374ba41SEd Maste dump_cfg_strarray_oneline(sChannelTimeout,
3336f374ba41SEd Maste o->num_channel_timeouts, o->channel_timeouts);
3337d4af9e69SDag-Erling Smørgrav
3338d4af9e69SDag-Erling Smørgrav /* other arguments */
3339d4af9e69SDag-Erling Smørgrav for (i = 0; i < o->num_subsystems; i++)
3340d4af9e69SDag-Erling Smørgrav printf("subsystem %s %s\n", o->subsystem_name[i],
3341d4af9e69SDag-Erling Smørgrav o->subsystem_args[i]);
3342d4af9e69SDag-Erling Smørgrav
3343d4af9e69SDag-Erling Smørgrav printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3344d4af9e69SDag-Erling Smørgrav o->max_startups_rate, o->max_startups);
334519261079SEd Maste printf("persourcemaxstartups ");
334619261079SEd Maste if (o->per_source_max_startups == INT_MAX)
334719261079SEd Maste printf("none\n");
334819261079SEd Maste else
334919261079SEd Maste printf("%d\n", o->per_source_max_startups);
335019261079SEd Maste printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
335119261079SEd Maste o->per_source_masklen_ipv6);
3352d4af9e69SDag-Erling Smørgrav
335347dd1d1bSDag-Erling Smørgrav s = NULL;
335447dd1d1bSDag-Erling Smørgrav for (i = 0; tunmode_desc[i].val != -1; i++) {
3355d4af9e69SDag-Erling Smørgrav if (tunmode_desc[i].val == o->permit_tun) {
3356d4af9e69SDag-Erling Smørgrav s = tunmode_desc[i].text;
3357d4af9e69SDag-Erling Smørgrav break;
3358d4af9e69SDag-Erling Smørgrav }
335947dd1d1bSDag-Erling Smørgrav }
3360d4af9e69SDag-Erling Smørgrav dump_cfg_string(sPermitTunnel, s);
3361d4af9e69SDag-Erling Smørgrav
3362e146993eSDag-Erling Smørgrav printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3363e146993eSDag-Erling Smørgrav printf("%s\n", iptos2str(o->ip_qos_bulk));
33644a421b63SDag-Erling Smørgrav
3365acc1a9efSDag-Erling Smørgrav printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3366e4a9863fSDag-Erling Smørgrav o->rekey_interval);
3367e4a9863fSDag-Erling Smørgrav
33684f52dfbbSDag-Erling Smørgrav printf("permitopen");
33694f52dfbbSDag-Erling Smørgrav if (o->num_permitted_opens == 0)
33704f52dfbbSDag-Erling Smørgrav printf(" any");
33714f52dfbbSDag-Erling Smørgrav else {
33724f52dfbbSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_opens; i++)
33734f52dfbbSDag-Erling Smørgrav printf(" %s", o->permitted_opens[i]);
33744f52dfbbSDag-Erling Smørgrav }
33754f52dfbbSDag-Erling Smørgrav printf("\n");
3376190cef3dSDag-Erling Smørgrav printf("permitlisten");
3377190cef3dSDag-Erling Smørgrav if (o->num_permitted_listens == 0)
3378190cef3dSDag-Erling Smørgrav printf(" any");
3379190cef3dSDag-Erling Smørgrav else {
3380190cef3dSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_listens; i++)
3381190cef3dSDag-Erling Smørgrav printf(" %s", o->permitted_listens[i]);
3382190cef3dSDag-Erling Smørgrav }
3383190cef3dSDag-Erling Smørgrav printf("\n");
3384190cef3dSDag-Erling Smørgrav
338519261079SEd Maste if (o->permit_user_env_allowlist == NULL) {
3386190cef3dSDag-Erling Smørgrav dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3387190cef3dSDag-Erling Smørgrav } else {
3388190cef3dSDag-Erling Smørgrav printf("permituserenvironment %s\n",
338919261079SEd Maste o->permit_user_env_allowlist);
3390190cef3dSDag-Erling Smørgrav }
3391190cef3dSDag-Erling Smørgrav
339219261079SEd Maste printf("pubkeyauthoptions");
339319261079SEd Maste if (o->pubkey_auth_options == 0)
339419261079SEd Maste printf(" none");
339519261079SEd Maste if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
339619261079SEd Maste printf(" touch-required");
339719261079SEd Maste if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
339819261079SEd Maste printf(" verify-required");
339919261079SEd Maste printf("\n");
34000fdf8faeSEd Maste
34010fdf8faeSEd Maste if (o->per_source_penalty.enabled) {
34020fdf8faeSEd Maste printf("persourcepenalties crash:%d authfail:%d noauth:%d "
34033d9fd9fcSEd Maste "grace-exceeded:%d refuseconnection:%d max:%d min:%d "
34043d9fd9fcSEd Maste "max-sources4:%d max-sources6:%d "
34053d9fd9fcSEd Maste "overflow:%s overflow6:%s\n",
34060fdf8faeSEd Maste o->per_source_penalty.penalty_crash,
34070fdf8faeSEd Maste o->per_source_penalty.penalty_authfail,
34080fdf8faeSEd Maste o->per_source_penalty.penalty_noauth,
34090fdf8faeSEd Maste o->per_source_penalty.penalty_grace,
34103d9fd9fcSEd Maste o->per_source_penalty.penalty_refuseconnection,
34110fdf8faeSEd Maste o->per_source_penalty.penalty_max,
34120fdf8faeSEd Maste o->per_source_penalty.penalty_min,
34130fdf8faeSEd Maste o->per_source_penalty.max_sources4,
34140fdf8faeSEd Maste o->per_source_penalty.max_sources6,
34150fdf8faeSEd Maste o->per_source_penalty.overflow_mode ==
34160fdf8faeSEd Maste PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
34170fdf8faeSEd Maste "deny-all" : "permissive",
34180fdf8faeSEd Maste o->per_source_penalty.overflow_mode6 ==
34190fdf8faeSEd Maste PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
34200fdf8faeSEd Maste "deny-all" : "permissive");
34210fdf8faeSEd Maste } else
34220fdf8faeSEd Maste printf("persourcepenalties no\n");
3423d4af9e69SDag-Erling Smørgrav }
3424