1 /* $OpenBSD: servconf.c,v 1.446 2026/04/02 07:38:14 djm Exp $ */
2 /*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 *
6 * As far as I am concerned, the code I have written for this software
7 * can be used freely for any purpose. Any derived versions of this
8 * software must be clearly marked as such, and if the derived work is
9 * incompatible with the protocol description in the RFC file, it must be
10 * called by a name other than "ssh" or "Secure Shell".
11 */
12
13 #include "includes.h"
14
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/queue.h>
18 #include <sys/stat.h>
19 #ifdef __OpenBSD__
20 #include <sys/sysctl.h>
21 #endif
22
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 #ifdef HAVE_NET_ROUTE_H
26 #include <net/route.h>
27 #endif
28
29 #include <ctype.h>
30 #include <glob.h>
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <stdarg.h>
40 #include <errno.h>
41 #include <util.h>
42
43 #include "xmalloc.h"
44 #include "ssh.h"
45 #include "log.h"
46 #include "sshbuf.h"
47 #include "misc.h"
48 #include "servconf.h"
49 #include "pathnames.h"
50 #include "cipher.h"
51 #include "sshkey.h"
52 #include "kex.h"
53 #include "mac.h"
54 #include "match.h"
55 #include "channels.h"
56 #include "groupaccess.h"
57 #include "canohost.h"
58 #include "packet.h"
59 #include "ssherr.h"
60 #include "hostfile.h"
61 #include "auth.h"
62 #include "myproposal.h"
63 #include "digest.h"
64 #include "version.h"
65
66 #if !defined(SSHD_PAM_SERVICE)
67 # define SSHD_PAM_SERVICE "sshd"
68 #endif
69
70 static void add_listen_addr(ServerOptions *, const char *,
71 const char *, int);
72 static void add_one_listen_addr(ServerOptions *, const char *,
73 const char *, int);
74 static void parse_server_config_depth(ServerOptions *options,
75 const char *filename, struct sshbuf *conf, struct include_list *includes,
76 struct connection_info *connectinfo, int flags, int *activep, int depth);
77
78 extern struct sshbuf *cfg;
79
80 /* Initializes the server options to their default values. */
81
82 void
initialize_server_options(ServerOptions * options)83 initialize_server_options(ServerOptions *options)
84 {
85 memset(options, 0, sizeof(*options));
86
87 /* Portable-specific options */
88 options->use_pam = -1;
89 options->pam_service_name = NULL;
90
91 /* Standard Options */
92 options->num_ports = 0;
93 options->ports_from_cmdline = 0;
94 options->queued_listen_addrs = NULL;
95 options->num_queued_listens = 0;
96 options->listen_addrs = NULL;
97 options->num_listen_addrs = 0;
98 options->address_family = -1;
99 options->routing_domain = NULL;
100 options->num_host_key_files = 0;
101 options->num_host_cert_files = 0;
102 options->host_key_agent = NULL;
103 options->pid_file = NULL;
104 options->login_grace_time = -1;
105 options->permit_root_login = PERMIT_NOT_SET;
106 options->ignore_rhosts = -1;
107 options->ignore_user_known_hosts = -1;
108 options->print_motd = -1;
109 options->print_lastlog = -1;
110 options->x11_forwarding = -1;
111 options->x11_display_offset = -1;
112 options->x11_use_localhost = -1;
113 options->permit_tty = -1;
114 options->permit_user_rc = -1;
115 options->xauth_location = NULL;
116 options->strict_modes = -1;
117 options->tcp_keep_alive = -1;
118 options->log_facility = SYSLOG_FACILITY_NOT_SET;
119 options->log_level = SYSLOG_LEVEL_NOT_SET;
120 options->num_log_verbose = 0;
121 options->log_verbose = NULL;
122 options->hostbased_authentication = -1;
123 options->hostbased_uses_name_from_packet_only = -1;
124 options->hostbased_accepted_algos = NULL;
125 options->hostkeyalgorithms = NULL;
126 options->pubkey_authentication = -1;
127 options->pubkey_auth_options = -1;
128 options->pubkey_accepted_algos = NULL;
129 options->kerberos_authentication = -1;
130 options->kerberos_or_local_passwd = -1;
131 options->kerberos_ticket_cleanup = -1;
132 options->kerberos_get_afs_token = -1;
133 options->gss_authentication=-1;
134 options->gss_cleanup_creds = -1;
135 options->gss_deleg_creds = -1;
136 options->gss_strict_acceptor = -1;
137 options->password_authentication = -1;
138 options->kbd_interactive_authentication = -1;
139 options->permit_empty_passwd = -1;
140 options->permit_user_env = -1;
141 options->permit_user_env_allowlist = NULL;
142 options->compression = -1;
143 options->rekey_limit = -1;
144 options->rekey_interval = -1;
145 options->allow_tcp_forwarding = -1;
146 options->allow_streamlocal_forwarding = -1;
147 options->allow_agent_forwarding = -1;
148 options->num_allow_users = 0;
149 options->num_deny_users = 0;
150 options->num_allow_groups = 0;
151 options->num_deny_groups = 0;
152 options->ciphers = NULL;
153 options->macs = NULL;
154 options->kex_algorithms = NULL;
155 options->ca_sign_algorithms = NULL;
156 options->fwd_opts.gateway_ports = -1;
157 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
158 options->fwd_opts.streamlocal_bind_unlink = -1;
159 options->num_subsystems = 0;
160 options->max_startups_begin = -1;
161 options->max_startups_rate = -1;
162 options->max_startups = -1;
163 options->per_source_max_startups = -1;
164 options->per_source_masklen_ipv4 = -1;
165 options->per_source_masklen_ipv6 = -1;
166 options->per_source_penalty_exempt = NULL;
167 options->per_source_penalty.enabled = -1;
168 options->per_source_penalty.max_sources4 = -1;
169 options->per_source_penalty.max_sources6 = -1;
170 options->per_source_penalty.overflow_mode = -1;
171 options->per_source_penalty.overflow_mode6 = -1;
172 options->per_source_penalty.penalty_crash = -1.0;
173 options->per_source_penalty.penalty_authfail = -1.0;
174 options->per_source_penalty.penalty_invaliduser = -1.0;
175 options->per_source_penalty.penalty_noauth = -1.0;
176 options->per_source_penalty.penalty_grace = -1.0;
177 options->per_source_penalty.penalty_refuseconnection = -1.0;
178 options->per_source_penalty.penalty_max = -1.0;
179 options->per_source_penalty.penalty_min = -1.0;
180 options->max_authtries = -1;
181 options->max_sessions = -1;
182 options->banner = NULL;
183 options->use_dns = -1;
184 options->client_alive_interval = -1;
185 options->client_alive_count_max = -1;
186 options->num_authkeys_files = 0;
187 options->num_accept_env = 0;
188 options->num_setenv = 0;
189 options->permit_tun = -1;
190 options->permitted_opens = NULL;
191 options->permitted_listens = NULL;
192 options->adm_forced_command = NULL;
193 options->chroot_directory = NULL;
194 options->authorized_keys_command = NULL;
195 options->authorized_keys_command_user = NULL;
196 options->revoked_keys_files = NULL;
197 options->num_revoked_keys_files = 0;
198 options->sk_provider = NULL;
199 options->trusted_user_ca_keys = NULL;
200 options->authorized_principals_file = NULL;
201 options->authorized_principals_command = NULL;
202 options->authorized_principals_command_user = NULL;
203 options->ip_qos_interactive = -1;
204 options->ip_qos_bulk = -1;
205 options->version_addendum = NULL;
206 options->fingerprint_hash = -1;
207 options->disable_forwarding = -1;
208 options->expose_userauth_info = -1;
209 options->required_rsa_size = -1;
210 options->channel_timeouts = NULL;
211 options->num_channel_timeouts = 0;
212 options->unused_connection_timeout = -1;
213 options->sshd_session_path = NULL;
214 options->sshd_auth_path = NULL;
215 options->refuse_connection = -1;
216 options->use_blocklist = -1;
217 }
218
219 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
220 static int
option_clear_or_none(const char * o)221 option_clear_or_none(const char *o)
222 {
223 return o == NULL || strcasecmp(o, "none") == 0;
224 }
225
226 static void
assemble_algorithms(ServerOptions * o)227 assemble_algorithms(ServerOptions *o)
228 {
229 char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
230 char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
231 int r;
232
233 all_cipher = cipher_alg_list(',', 0);
234 all_mac = mac_alg_list(',');
235 all_kex = kex_alg_list(',');
236 all_key = sshkey_alg_list(0, 0, 1, ',');
237 all_sig = sshkey_alg_list(0, 1, 1, ',');
238 /* remove unsupported algos from default lists */
239 def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
240 def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
241 def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
242 def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
243 def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
244 #define ASSEMBLE(what, defaults, all) \
245 do { \
246 if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
247 fatal_fr(r, "%s", #what); \
248 } while (0)
249 ASSEMBLE(ciphers, def_cipher, all_cipher);
250 ASSEMBLE(macs, def_mac, all_mac);
251 ASSEMBLE(kex_algorithms, def_kex, all_kex);
252 ASSEMBLE(hostkeyalgorithms, def_key, all_key);
253 ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
254 ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
255 ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
256 #undef ASSEMBLE
257 free(all_cipher);
258 free(all_mac);
259 free(all_kex);
260 free(all_key);
261 free(all_sig);
262 free(def_cipher);
263 free(def_mac);
264 free(def_kex);
265 free(def_key);
266 free(def_sig);
267 }
268
269 static const char *defaultkey = "[default]";
270
271 void
servconf_add_hostkey(const char * file,const int line,ServerOptions * options,const char * path,int userprovided)272 servconf_add_hostkey(const char *file, const int line,
273 ServerOptions *options, const char *path, int userprovided)
274 {
275 char *apath = derelativise_path(path);
276
277 if (file == defaultkey && access(path, R_OK) != 0)
278 return;
279 opt_array_append2(file, line, "HostKey",
280 &options->host_key_files, &options->host_key_file_userprovided,
281 &options->num_host_key_files, apath, userprovided);
282 free(apath);
283 }
284
285 void
servconf_add_hostcert(const char * file,const int line,ServerOptions * options,const char * path)286 servconf_add_hostcert(const char *file, const int line,
287 ServerOptions *options, const char *path)
288 {
289 char *apath = derelativise_path(path);
290
291 opt_array_append(file, line, "HostCertificate",
292 &options->host_cert_files, &options->num_host_cert_files, apath);
293 free(apath);
294 }
295
296 void
fill_default_server_options(ServerOptions * options)297 fill_default_server_options(ServerOptions *options)
298 {
299 u_int i;
300
301 /* Portable-specific options */
302 if (options->use_pam == -1)
303 options->use_pam = 1;
304 if (options->pam_service_name == NULL)
305 options->pam_service_name = xstrdup(SSHD_PAM_SERVICE);
306
307 /* Standard Options */
308 if (options->num_host_key_files == 0) {
309 /* fill default hostkeys for protocols */
310 servconf_add_hostkey(defaultkey, 0, options,
311 _PATH_HOST_RSA_KEY_FILE, 0);
312 #ifdef OPENSSL_HAS_ECC
313 servconf_add_hostkey(defaultkey, 0, options,
314 _PATH_HOST_ECDSA_KEY_FILE, 0);
315 #endif
316 servconf_add_hostkey(defaultkey, 0, options,
317 _PATH_HOST_ED25519_KEY_FILE, 0);
318 }
319 if (options->num_host_key_files == 0)
320 fatal("No host key files found");
321 /* No certificates by default */
322 if (options->num_ports == 0)
323 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
324 if (options->address_family == -1)
325 options->address_family = AF_UNSPEC;
326 if (options->listen_addrs == NULL)
327 add_listen_addr(options, NULL, NULL, 0);
328 if (options->pid_file == NULL)
329 options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
330 if (options->moduli_file == NULL)
331 options->moduli_file = xstrdup(_PATH_DH_MODULI);
332 if (options->login_grace_time == -1)
333 options->login_grace_time = 120;
334 if (options->permit_root_login == PERMIT_NOT_SET)
335 options->permit_root_login = PERMIT_NO;
336 if (options->ignore_rhosts == -1)
337 options->ignore_rhosts = 1;
338 if (options->ignore_user_known_hosts == -1)
339 options->ignore_user_known_hosts = 0;
340 if (options->print_motd == -1)
341 options->print_motd = 1;
342 if (options->print_lastlog == -1)
343 options->print_lastlog = 1;
344 if (options->x11_forwarding == -1)
345 options->x11_forwarding = 0;
346 if (options->x11_display_offset == -1)
347 options->x11_display_offset = 10;
348 if (options->x11_use_localhost == -1)
349 options->x11_use_localhost = 1;
350 if (options->xauth_location == NULL)
351 options->xauth_location = xstrdup(_PATH_XAUTH);
352 if (options->permit_tty == -1)
353 options->permit_tty = 1;
354 if (options->permit_user_rc == -1)
355 options->permit_user_rc = 1;
356 if (options->strict_modes == -1)
357 options->strict_modes = 1;
358 if (options->tcp_keep_alive == -1)
359 options->tcp_keep_alive = 1;
360 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
361 options->log_facility = SYSLOG_FACILITY_AUTH;
362 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
363 options->log_level = SYSLOG_LEVEL_INFO;
364 if (options->hostbased_authentication == -1)
365 options->hostbased_authentication = 0;
366 if (options->hostbased_uses_name_from_packet_only == -1)
367 options->hostbased_uses_name_from_packet_only = 0;
368 if (options->pubkey_authentication == -1)
369 options->pubkey_authentication = 1;
370 if (options->pubkey_auth_options == -1)
371 options->pubkey_auth_options = 0;
372 if (options->kerberos_authentication == -1)
373 options->kerberos_authentication = 0;
374 if (options->kerberos_or_local_passwd == -1)
375 options->kerberos_or_local_passwd = 1;
376 if (options->kerberos_ticket_cleanup == -1)
377 options->kerberos_ticket_cleanup = 1;
378 if (options->kerberos_get_afs_token == -1)
379 options->kerberos_get_afs_token = 0;
380 if (options->gss_authentication == -1)
381 options->gss_authentication = 0;
382 if (options->gss_cleanup_creds == -1)
383 options->gss_cleanup_creds = 1;
384 if (options->gss_deleg_creds == -1)
385 options->gss_deleg_creds = 1;
386 if (options->gss_strict_acceptor == -1)
387 options->gss_strict_acceptor = 1;
388 if (options->password_authentication == -1)
389 options->password_authentication = 0;
390 if (options->kbd_interactive_authentication == -1)
391 options->kbd_interactive_authentication = 1;
392 if (options->permit_empty_passwd == -1)
393 options->permit_empty_passwd = 0;
394 if (options->permit_user_env == -1) {
395 options->permit_user_env = 0;
396 options->permit_user_env_allowlist = NULL;
397 }
398 if (options->compression == -1)
399 #ifdef WITH_ZLIB
400 options->compression = COMP_DELAYED;
401 #else
402 options->compression = COMP_NONE;
403 #endif
404
405 if (options->rekey_limit == -1)
406 options->rekey_limit = 0;
407 if (options->rekey_interval == -1)
408 options->rekey_interval = 0;
409 if (options->allow_tcp_forwarding == -1)
410 options->allow_tcp_forwarding = FORWARD_ALLOW;
411 if (options->allow_streamlocal_forwarding == -1)
412 options->allow_streamlocal_forwarding = FORWARD_ALLOW;
413 if (options->allow_agent_forwarding == -1)
414 options->allow_agent_forwarding = 1;
415 if (options->fwd_opts.gateway_ports == -1)
416 options->fwd_opts.gateway_ports = 0;
417 if (options->max_startups == -1)
418 options->max_startups = 100;
419 if (options->max_startups_rate == -1)
420 options->max_startups_rate = 30; /* 30% */
421 if (options->max_startups_begin == -1)
422 options->max_startups_begin = 10;
423 if (options->per_source_max_startups == -1)
424 options->per_source_max_startups = INT_MAX;
425 if (options->per_source_masklen_ipv4 == -1)
426 options->per_source_masklen_ipv4 = 32;
427 if (options->per_source_masklen_ipv6 == -1)
428 options->per_source_masklen_ipv6 = 128;
429 if (options->per_source_penalty.enabled == -1)
430 options->per_source_penalty.enabled = 1;
431 if (options->per_source_penalty.max_sources4 == -1)
432 options->per_source_penalty.max_sources4 = 65536;
433 if (options->per_source_penalty.max_sources6 == -1)
434 options->per_source_penalty.max_sources6 = 65536;
435 if (options->per_source_penalty.overflow_mode == -1)
436 options->per_source_penalty.overflow_mode = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
437 if (options->per_source_penalty.overflow_mode6 == -1)
438 options->per_source_penalty.overflow_mode6 = options->per_source_penalty.overflow_mode;
439 if (options->per_source_penalty.penalty_crash < 0.0)
440 options->per_source_penalty.penalty_crash = 90.0;
441 if (options->per_source_penalty.penalty_grace < 0.0)
442 options->per_source_penalty.penalty_grace = 10.0;
443 if (options->per_source_penalty.penalty_authfail < 0.0)
444 options->per_source_penalty.penalty_authfail = 5.0;
445 if (options->per_source_penalty.penalty_invaliduser < 0.0)
446 options->per_source_penalty.penalty_invaliduser = 5.0;
447 if (options->per_source_penalty.penalty_noauth < 0.0)
448 options->per_source_penalty.penalty_noauth = 1.0;
449 if (options->per_source_penalty.penalty_refuseconnection < 0.0)
450 options->per_source_penalty.penalty_refuseconnection = 10.0;
451 if (options->per_source_penalty.penalty_min < 0.0)
452 options->per_source_penalty.penalty_min = 15.0;
453 if (options->per_source_penalty.penalty_max < 0.0)
454 options->per_source_penalty.penalty_max = 600.0;
455 if (options->max_authtries == -1)
456 options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
457 if (options->max_sessions == -1)
458 options->max_sessions = DEFAULT_SESSIONS_MAX;
459 if (options->use_dns == -1)
460 options->use_dns = 1;
461 if (options->client_alive_interval == -1)
462 options->client_alive_interval = 0;
463 if (options->client_alive_count_max == -1)
464 options->client_alive_count_max = 3;
465 if (options->num_authkeys_files == 0) {
466 opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
467 &options->authorized_keys_files,
468 &options->num_authkeys_files,
469 _PATH_SSH_USER_PERMITTED_KEYS);
470 opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
471 &options->authorized_keys_files,
472 &options->num_authkeys_files,
473 _PATH_SSH_USER_PERMITTED_KEYS2);
474 }
475 if (options->permit_tun == -1)
476 options->permit_tun = SSH_TUNMODE_NO;
477 if (options->ip_qos_interactive == -1)
478 options->ip_qos_interactive = IPTOS_DSCP_EF;
479 if (options->ip_qos_bulk == -1)
480 options->ip_qos_bulk = IPTOS_DSCP_CS0;
481 if (options->version_addendum == NULL)
482 options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
483 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
484 options->fwd_opts.streamlocal_bind_mask = 0177;
485 if (options->fwd_opts.streamlocal_bind_unlink == -1)
486 options->fwd_opts.streamlocal_bind_unlink = 0;
487 if (options->fingerprint_hash == -1)
488 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
489 if (options->disable_forwarding == -1)
490 options->disable_forwarding = 0;
491 if (options->expose_userauth_info == -1)
492 options->expose_userauth_info = 0;
493 if (options->sk_provider == NULL)
494 options->sk_provider = xstrdup("internal");
495 if (options->required_rsa_size == -1)
496 options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
497 if (options->unused_connection_timeout == -1)
498 options->unused_connection_timeout = 0;
499 if (options->sshd_session_path == NULL)
500 options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION);
501 if (options->sshd_auth_path == NULL)
502 options->sshd_auth_path = xstrdup(_PATH_SSHD_AUTH);
503 if (options->refuse_connection == -1)
504 options->refuse_connection = 0;
505 if (options->use_blocklist == -1)
506 options->use_blocklist = 0;
507
508 assemble_algorithms(options);
509
510 #define CLEAR_ON_NONE(v) \
511 do { \
512 if (option_clear_or_none(v)) { \
513 free(v); \
514 v = NULL; \
515 } \
516 } while(0)
517 #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
518 do { \
519 if (options->nv == 1 && \
520 strcasecmp(options->v[0], none) == 0) { \
521 free(options->v[0]); \
522 free(options->v); \
523 options->v = NULL; \
524 options->nv = 0; \
525 } \
526 } while (0)
527 CLEAR_ON_NONE(options->pid_file);
528 CLEAR_ON_NONE(options->xauth_location);
529 CLEAR_ON_NONE(options->banner);
530 CLEAR_ON_NONE(options->trusted_user_ca_keys);
531 CLEAR_ON_NONE(options->sk_provider);
532 CLEAR_ON_NONE(options->authorized_principals_file);
533 CLEAR_ON_NONE(options->adm_forced_command);
534 CLEAR_ON_NONE(options->chroot_directory);
535 CLEAR_ON_NONE(options->routing_domain);
536 CLEAR_ON_NONE(options->host_key_agent);
537 CLEAR_ON_NONE(options->per_source_penalty_exempt);
538
539 for (i = 0; i < options->num_host_key_files; i++)
540 CLEAR_ON_NONE(options->host_key_files[i]);
541 for (i = 0; i < options->num_host_cert_files; i++)
542 CLEAR_ON_NONE(options->host_cert_files[i]);
543
544 CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
545 CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
546 CLEAR_ON_NONE_ARRAY(revoked_keys_files, num_revoked_keys_files, "none");
547 CLEAR_ON_NONE_ARRAY(authorized_keys_files, num_authkeys_files, "none");
548 #undef CLEAR_ON_NONE
549 #undef CLEAR_ON_NONE_ARRAY
550 }
551
552 /* Keyword tokens. */
553 typedef enum {
554 sBadOption, /* == unknown option */
555 /* Portable-specific options */
556 sUsePAM, sPAMServiceName,
557 /* Standard Options */
558 sPort, sHostKeyFile, sLoginGraceTime,
559 sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
560 sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
561 sKerberosGetAFSToken, sPasswordAuthentication,
562 sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
563 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
564 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
565 sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
566 sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
567 sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
568 sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
569 sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
570 sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
571 sBanner, sUseDNS, sHostbasedAuthentication,
572 sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
573 sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
574 sPerSourcePenalties, sPerSourcePenaltyExemptList,
575 sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
576 sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds, sGssStrictAcceptor,
577 sAcceptEnv, sSetEnv, sPermitTunnel,
578 sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
579 sUsePrivilegeSeparation, sAllowAgentForwarding,
580 sHostCertificate, sInclude,
581 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
582 sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
583 sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
584 sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
585 sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
586 sStreamLocalBindMask, sStreamLocalBindUnlink,
587 sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
588 sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
589 sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
590 sSshdSessionPath, sSshdAuthPath, sRefuseConnection,
591 sUseBlocklist,
592 sDeprecated, sIgnore, sUnsupported
593 } ServerOpCodes;
594
595 #define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */
596 #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
597 #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
598 #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */
599 #define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */
600
601 /* Textual representation of the tokens. */
602 static struct {
603 const char *name;
604 ServerOpCodes opcode;
605 u_int flags;
606 } keywords[] = {
607 /* Portable-specific options */
608 #ifdef USE_PAM
609 { "usepam", sUsePAM, SSHCFG_GLOBAL },
610 { "pamservicename", sPAMServiceName, SSHCFG_ALL },
611 #else
612 { "usepam", sUnsupported, SSHCFG_GLOBAL },
613 { "pamservicename", sUnsupported, SSHCFG_ALL },
614 #endif
615 { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
616 /* Standard Options */
617 { "port", sPort, SSHCFG_GLOBAL },
618 { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
619 { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
620 { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
621 { "pidfile", sPidFile, SSHCFG_GLOBAL },
622 { "modulifile", sModuliFile, SSHCFG_GLOBAL },
623 { "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
624 { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
625 { "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
626 { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
627 { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
628 { "loglevel", sLogLevel, SSHCFG_ALL },
629 { "logverbose", sLogVerbose, SSHCFG_ALL },
630 { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
631 { "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
632 { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
633 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
634 { "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
635 { "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
636 { "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
637 { "rsaauthentication", sDeprecated, SSHCFG_ALL },
638 { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
639 { "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
640 { "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
641 { "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
642 { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
643 #ifdef KRB5
644 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
645 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
646 { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
647 #ifdef USE_AFS
648 { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
649 #else
650 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
651 #endif
652 #else
653 { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
654 { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
655 { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
656 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
657 #endif
658 { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
659 { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
660 #ifdef GSSAPI
661 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
662 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
663 { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_GLOBAL },
664 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
665 #else
666 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
667 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
668 { "gssapidelegatecredentials", sUnsupported, SSHCFG_GLOBAL },
669 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
670 #endif
671 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
672 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
673 { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
674 { "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
675 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
676 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
677 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
678 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
679 #ifdef DISABLE_LASTLOG
680 { "printlastlog", sUnsupported, SSHCFG_GLOBAL },
681 #else
682 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
683 #endif
684 { "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
685 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
686 { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
687 { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
688 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
689 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
690 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
691 { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
692 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
693 { "uselogin", sDeprecated, SSHCFG_GLOBAL },
694 { "compression", sCompression, SSHCFG_GLOBAL },
695 { "rekeylimit", sRekeyLimit, SSHCFG_ALL },
696 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
697 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
698 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
699 { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
700 { "allowusers", sAllowUsers, SSHCFG_ALL },
701 { "denyusers", sDenyUsers, SSHCFG_ALL },
702 { "allowgroups", sAllowGroups, SSHCFG_ALL },
703 { "denygroups", sDenyGroups, SSHCFG_ALL },
704 { "ciphers", sCiphers, SSHCFG_GLOBAL },
705 { "macs", sMacs, SSHCFG_GLOBAL },
706 { "protocol", sIgnore, SSHCFG_GLOBAL },
707 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
708 { "subsystem", sSubsystem, SSHCFG_ALL },
709 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
710 { "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
711 { "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
712 { "persourcepenalties", sPerSourcePenalties, SSHCFG_GLOBAL },
713 { "persourcepenaltyexemptlist", sPerSourcePenaltyExemptList, SSHCFG_GLOBAL },
714 { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
715 { "maxsessions", sMaxSessions, SSHCFG_ALL },
716 { "banner", sBanner, SSHCFG_ALL },
717 { "usedns", sUseDNS, SSHCFG_GLOBAL },
718 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
719 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
720 { "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
721 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
722 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
723 { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
724 { "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
725 { "acceptenv", sAcceptEnv, SSHCFG_ALL },
726 { "setenv", sSetEnv, SSHCFG_ALL },
727 { "permittunnel", sPermitTunnel, SSHCFG_ALL },
728 { "permittty", sPermitTTY, SSHCFG_ALL },
729 { "permituserrc", sPermitUserRC, SSHCFG_ALL },
730 { "match", sMatch, SSHCFG_ALL },
731 { "permitopen", sPermitOpen, SSHCFG_ALL },
732 { "permitlisten", sPermitListen, SSHCFG_ALL },
733 { "forcecommand", sForceCommand, SSHCFG_ALL },
734 { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
735 { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
736 { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
737 { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
738 { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
739 { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
740 { "include", sInclude, SSHCFG_ALL },
741 { "ipqos", sIPQoS, SSHCFG_ALL },
742 { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
743 { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
744 { "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
745 { "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
746 { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
747 { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
748 { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
749 { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
750 { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
751 { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
752 { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
753 { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
754 { "rdomain", sRDomain, SSHCFG_ALL },
755 { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
756 { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
757 { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
758 { "channeltimeout", sChannelTimeout, SSHCFG_ALL },
759 { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
760 { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL },
761 { "sshdauthpath", sSshdAuthPath, SSHCFG_GLOBAL },
762 { "refuseconnection", sRefuseConnection, SSHCFG_ALL },
763 { "useblocklist", sUseBlocklist, SSHCFG_GLOBAL },
764 { "useblacklist", sUseBlocklist, SSHCFG_GLOBAL }, /* alias */
765
766 { NULL, sBadOption, 0 }
767 };
768
769 static struct {
770 int val;
771 char *text;
772 } tunmode_desc[] = {
773 { SSH_TUNMODE_NO, "no" },
774 { SSH_TUNMODE_POINTOPOINT, "point-to-point" },
775 { SSH_TUNMODE_ETHERNET, "ethernet" },
776 { SSH_TUNMODE_YES, "yes" },
777 { -1, NULL }
778 };
779
780 /* Returns an opcode name from its number */
781
782 static const char *
lookup_opcode_name(ServerOpCodes code)783 lookup_opcode_name(ServerOpCodes code)
784 {
785 u_int i;
786
787 for (i = 0; keywords[i].name != NULL; i++)
788 if (keywords[i].opcode == code)
789 return(keywords[i].name);
790 return "UNKNOWN";
791 }
792
793
794 /*
795 * Returns the number of the token pointed to by cp or sBadOption.
796 */
797
798 static ServerOpCodes
parse_token(const char * cp,const char * filename,int linenum,u_int * flags)799 parse_token(const char *cp, const char *filename,
800 int linenum, u_int *flags)
801 {
802 u_int i;
803
804 for (i = 0; keywords[i].name; i++)
805 if (strcasecmp(cp, keywords[i].name) == 0) {
806 *flags = keywords[i].flags;
807 return keywords[i].opcode;
808 }
809
810 error("%s: line %d: Bad configuration option: %s",
811 filename, linenum, cp);
812 return sBadOption;
813 }
814
815 char *
derelativise_path(const char * path)816 derelativise_path(const char *path)
817 {
818 char *expanded, *ret, cwd[PATH_MAX];
819
820 if (strcasecmp(path, "none") == 0)
821 return xstrdup("none");
822 expanded = tilde_expand_filename(path, getuid());
823 if (path_absolute(expanded))
824 return expanded;
825 if (getcwd(cwd, sizeof(cwd)) == NULL)
826 fatal_f("getcwd: %s", strerror(errno));
827 xasprintf(&ret, "%s/%s", cwd, expanded);
828 free(expanded);
829 return ret;
830 }
831
832 static void
add_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)833 add_listen_addr(ServerOptions *options, const char *addr,
834 const char *rdomain, int port)
835 {
836 u_int i;
837
838 if (port > 0)
839 add_one_listen_addr(options, addr, rdomain, port);
840 else {
841 for (i = 0; i < options->num_ports; i++) {
842 add_one_listen_addr(options, addr, rdomain,
843 options->ports[i]);
844 }
845 }
846 }
847
848 static void
add_one_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)849 add_one_listen_addr(ServerOptions *options, const char *addr,
850 const char *rdomain, int port)
851 {
852 struct addrinfo hints, *ai, *aitop;
853 char strport[NI_MAXSERV];
854 int gaierr;
855 u_int i;
856
857 /* Find listen_addrs entry for this rdomain */
858 for (i = 0; i < options->num_listen_addrs; i++) {
859 if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
860 break;
861 if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
862 continue;
863 if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
864 break;
865 }
866 if (i >= options->num_listen_addrs) {
867 /* No entry for this rdomain; allocate one */
868 if (i >= INT_MAX)
869 fatal_f("too many listen addresses");
870 options->listen_addrs = xrecallocarray(options->listen_addrs,
871 options->num_listen_addrs, options->num_listen_addrs + 1,
872 sizeof(*options->listen_addrs));
873 i = options->num_listen_addrs++;
874 if (rdomain != NULL)
875 options->listen_addrs[i].rdomain = xstrdup(rdomain);
876 }
877 /* options->listen_addrs[i] points to the addresses for this rdomain */
878
879 memset(&hints, 0, sizeof(hints));
880 hints.ai_family = options->address_family;
881 hints.ai_socktype = SOCK_STREAM;
882 hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
883 snprintf(strport, sizeof strport, "%d", port);
884 if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
885 fatal("bad addr or host: %s (%s)",
886 addr ? addr : "<NULL>",
887 ssh_gai_strerror(gaierr));
888 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
889 ;
890 ai->ai_next = options->listen_addrs[i].addrs;
891 options->listen_addrs[i].addrs = aitop;
892 }
893
894 /* Returns nonzero if the routing domain name is valid */
895 static int
valid_rdomain(const char * name)896 valid_rdomain(const char *name)
897 {
898 #if defined(HAVE_SYS_VALID_RDOMAIN)
899 return sys_valid_rdomain(name);
900 #elif defined(__OpenBSD__)
901 const char *errstr;
902 long long num;
903 struct rt_tableinfo info;
904 int mib[6];
905 size_t miblen = sizeof(mib);
906
907 if (name == NULL)
908 return 1;
909
910 num = strtonum(name, 0, 255, &errstr);
911 if (errstr != NULL)
912 return 0;
913
914 /* Check whether the table actually exists */
915 memset(mib, 0, sizeof(mib));
916 mib[0] = CTL_NET;
917 mib[1] = PF_ROUTE;
918 mib[4] = NET_RT_TABLE;
919 mib[5] = (int)num;
920 if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
921 return 0;
922
923 return 1;
924 #else /* defined(__OpenBSD__) */
925 error("Routing domains are not supported on this platform");
926 return 0;
927 #endif
928 }
929
930 /*
931 * Queue a ListenAddress to be processed once we have all of the Ports
932 * and AddressFamily options.
933 */
934 static void
queue_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)935 queue_listen_addr(ServerOptions *options, const char *addr,
936 const char *rdomain, int port)
937 {
938 struct queued_listenaddr *qla;
939
940 options->queued_listen_addrs = xrecallocarray(
941 options->queued_listen_addrs,
942 options->num_queued_listens, options->num_queued_listens + 1,
943 sizeof(*options->queued_listen_addrs));
944 qla = &options->queued_listen_addrs[options->num_queued_listens++];
945 qla->addr = xstrdup(addr);
946 qla->port = port;
947 qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
948 }
949
950 /*
951 * Process queued (text) ListenAddress entries.
952 */
953 static void
process_queued_listen_addrs(ServerOptions * options)954 process_queued_listen_addrs(ServerOptions *options)
955 {
956 u_int i;
957 struct queued_listenaddr *qla;
958
959 if (options->num_ports == 0)
960 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
961 if (options->address_family == -1)
962 options->address_family = AF_UNSPEC;
963
964 for (i = 0; i < options->num_queued_listens; i++) {
965 qla = &options->queued_listen_addrs[i];
966 add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
967 free(qla->addr);
968 free(qla->rdomain);
969 }
970 free(options->queued_listen_addrs);
971 options->queued_listen_addrs = NULL;
972 options->num_queued_listens = 0;
973 }
974
975 /*
976 * The strategy for the Match blocks is that the config file is parsed twice.
977 *
978 * The first time is at startup. activep is initialized to 1 and the
979 * directives in the global context are processed and acted on. Hitting a
980 * Match directive unsets activep and the directives inside the block are
981 * checked for syntax only.
982 *
983 * The second time is after a connection has been established but before
984 * authentication. activep is initialized to 2 and global config directives
985 * are ignored since they have already been processed. If the criteria in a
986 * Match block is met, activep is set and the subsequent directives
987 * processed and actioned until EOF or another Match block unsets it. Any
988 * options set are copied into the main server config.
989 *
990 * Potential additions/improvements:
991 * - Add Match support for pre-kex directives, eg. Ciphers.
992 *
993 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
994 * Match Address 192.168.0.*
995 * Tag trusted
996 * Match Group wheel
997 * Tag trusted
998 * Match Tag trusted
999 * AllowTcpForwarding yes
1000 * GatewayPorts clientspecified
1001 * [...]
1002 *
1003 * - Add a PermittedChannelRequests directive
1004 * Match Group shell
1005 * PermittedChannelRequests session,forwarded-tcpip
1006 */
1007
1008 static int
match_cfg_line_group(const char * grps,int line,const char * user)1009 match_cfg_line_group(const char *grps, int line, const char *user)
1010 {
1011 int result = 0;
1012 struct passwd *pw;
1013
1014 if (user == NULL)
1015 goto out;
1016
1017 if ((pw = getpwnam(user)) == NULL) {
1018 debug("Can't match group at line %d because user %.100s does "
1019 "not exist", line, user);
1020 } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1021 debug("Can't Match group because user %.100s not in any group "
1022 "at line %d", user, line);
1023 } else if (ga_match_pattern_list(grps) != 1) {
1024 debug("user %.100s does not match group list %.100s at line %d",
1025 user, grps, line);
1026 } else {
1027 debug("user %.100s matched group list %.100s at line %d", user,
1028 grps, line);
1029 result = 1;
1030 }
1031 out:
1032 ga_free();
1033 return result;
1034 }
1035
1036 static void
match_test_missing_fatal(const char * criteria,const char * attrib)1037 match_test_missing_fatal(const char *criteria, const char *attrib)
1038 {
1039 fatal("'Match %s' in configuration but '%s' not in connection "
1040 "test specification.", criteria, attrib);
1041 }
1042
1043 /*
1044 * All of the attributes on a single Match line are ANDed together, so we need
1045 * to check every attribute and set the result to zero if any attribute does
1046 * not match.
1047 */
1048 static int
match_cfg_line(const char * full_line,int * acp,char *** avp,int line,struct connection_info * ci)1049 match_cfg_line(const char *full_line, int *acp, char ***avp,
1050 int line, struct connection_info *ci)
1051 {
1052 int result = 1, attributes = 0, port;
1053 char *arg, *attrib = NULL, *oattrib;
1054
1055 if (ci == NULL) {
1056 debug3("checking syntax for 'Match %s' on line %d",
1057 full_line, line);
1058 } else {
1059 debug3("checking match for '%s' user %s%s host %s addr %s "
1060 "laddr %s lport %d on line %d", full_line,
1061 ci->user ? ci->user : "(null)",
1062 ci->user_invalid ? " (invalid)" : "",
1063 ci->host ? ci->host : "(null)",
1064 ci->address ? ci->address : "(null)",
1065 ci->laddress ? ci->laddress : "(null)", ci->lport, line);
1066 }
1067
1068 while ((oattrib = argv_next(acp, avp)) != NULL) {
1069 /* Terminate on comment */
1070 if (*oattrib == '#') {
1071 argv_consume(acp); /* mark all arguments consumed */
1072 break;
1073 }
1074 attrib = xstrdup(oattrib);
1075 arg = NULL;
1076 attributes++;
1077 /* Criterion "all" has no argument and must appear alone */
1078 if (strcasecmp(attrib, "all") == 0) {
1079 if (attributes > 1 ||
1080 ((arg = argv_next(acp, avp)) != NULL &&
1081 *arg != '\0' && *arg != '#')) {
1082 error("'all' cannot be combined with other "
1083 "Match attributes");
1084 result = -1;
1085 goto out;
1086 }
1087 if (arg != NULL && *arg == '#')
1088 argv_consume(acp); /* consume remaining args */
1089 result = 1;
1090 goto out;
1091 }
1092 /* Criterion "invalid-user" also has no argument */
1093 if (strcasecmp(attrib, "invalid-user") == 0) {
1094 if (ci == NULL) {
1095 result = 0;
1096 goto next;
1097 }
1098 if (ci->user_invalid == 0)
1099 result = 0;
1100 else
1101 debug("matched invalid-user at line %d", line);
1102 goto next;
1103 }
1104
1105 /* Keep this list in sync with below */
1106 if (strprefix(attrib, "user=", 1) != NULL ||
1107 strprefix(attrib, "group=", 1) != NULL ||
1108 strprefix(attrib, "host=", 1) != NULL ||
1109 strprefix(attrib, "address=", 1) != NULL ||
1110 strprefix(attrib, "localaddress=", 1) != NULL ||
1111 strprefix(attrib, "localport=", 1) != NULL ||
1112 strprefix(attrib, "rdomain=", 1) != NULL ||
1113 strprefix(attrib, "version=", 1) != NULL) {
1114 arg = strchr(attrib, '=');
1115 *(arg++) = '\0';
1116 } else {
1117 arg = argv_next(acp, avp);
1118 }
1119
1120 /* All other criteria require an argument */
1121 if (arg == NULL || *arg == '\0' || *arg == '#') {
1122 error("Missing Match criteria for %s", attrib);
1123 result = -1;
1124 goto out;
1125 }
1126 if (strcasecmp(attrib, "user") == 0) {
1127 if (ci == NULL || (ci->test && ci->user == NULL)) {
1128 result = 0;
1129 goto next;
1130 }
1131 if (ci->user == NULL)
1132 match_test_missing_fatal("User", "user");
1133 if (match_usergroup_pattern_list(ci->user, arg) != 1)
1134 result = 0;
1135 else
1136 debug("user %.100s matched 'User %.100s' at "
1137 "line %d", ci->user, arg, line);
1138 } else if (strcasecmp(attrib, "group") == 0) {
1139 if (ci == NULL || (ci->test && ci->user == NULL)) {
1140 result = 0;
1141 goto next;
1142 }
1143 if (ci->user == NULL)
1144 match_test_missing_fatal("Group", "user");
1145 switch (match_cfg_line_group(arg, line, ci->user)) {
1146 case -1:
1147 result = -1;
1148 goto out;
1149 case 0:
1150 result = 0;
1151 }
1152 } else if (strcasecmp(attrib, "host") == 0) {
1153 if (ci == NULL || (ci->test && ci->host == NULL)) {
1154 result = 0;
1155 goto next;
1156 }
1157 if (ci->host == NULL)
1158 match_test_missing_fatal("Host", "host");
1159 if (match_hostname(ci->host, arg) != 1)
1160 result = 0;
1161 else
1162 debug("connection from %.100s matched 'Host "
1163 "%.100s' at line %d", ci->host, arg, line);
1164 } else if (strcasecmp(attrib, "address") == 0) {
1165 if (ci == NULL || (ci->test && ci->address == NULL)) {
1166 if (addr_match_list(NULL, arg) != 0)
1167 fatal("Invalid Match address argument "
1168 "'%s' at line %d", arg, line);
1169 result = 0;
1170 goto next;
1171 }
1172 if (ci->address == NULL)
1173 match_test_missing_fatal("Address", "addr");
1174 switch (addr_match_list(ci->address, arg)) {
1175 case 1:
1176 debug("connection from %.100s matched 'Address "
1177 "%.100s' at line %d", ci->address, arg, line);
1178 break;
1179 case 0:
1180 case -1:
1181 result = 0;
1182 break;
1183 case -2:
1184 result = -1;
1185 goto out;
1186 }
1187 } else if (strcasecmp(attrib, "localaddress") == 0){
1188 if (ci == NULL || (ci->test && ci->laddress == NULL)) {
1189 if (addr_match_list(NULL, arg) != 0)
1190 fatal("Invalid Match localaddress "
1191 "argument '%s' at line %d", arg,
1192 line);
1193 result = 0;
1194 goto next;
1195 }
1196 if (ci->laddress == NULL)
1197 match_test_missing_fatal("LocalAddress",
1198 "laddr");
1199 switch (addr_match_list(ci->laddress, arg)) {
1200 case 1:
1201 debug("connection from %.100s matched "
1202 "'LocalAddress %.100s' at line %d",
1203 ci->laddress, arg, line);
1204 break;
1205 case 0:
1206 case -1:
1207 result = 0;
1208 break;
1209 case -2:
1210 result = -1;
1211 goto out;
1212 }
1213 } else if (strcasecmp(attrib, "localport") == 0) {
1214 if ((port = a2port(arg)) == -1) {
1215 error("Invalid LocalPort '%s' on Match line",
1216 arg);
1217 result = -1;
1218 goto out;
1219 }
1220 if (ci == NULL || (ci->test && ci->lport == -1)) {
1221 result = 0;
1222 goto next;
1223 }
1224 if (ci->lport == 0)
1225 match_test_missing_fatal("LocalPort", "lport");
1226 /* TODO support port lists */
1227 if (port == ci->lport)
1228 debug("connection from %.100s matched "
1229 "'LocalPort %d' at line %d",
1230 ci->laddress, port, line);
1231 else
1232 result = 0;
1233 } else if (strcasecmp(attrib, "rdomain") == 0) {
1234 if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
1235 result = 0;
1236 goto next;
1237 }
1238 if (ci->rdomain == NULL)
1239 match_test_missing_fatal("RDomain", "rdomain");
1240 if (match_pattern_list(ci->rdomain, arg, 0) != 1)
1241 result = 0;
1242 else
1243 debug("connection RDomain %.100s matched "
1244 "'RDomain %.100s' at line %d",
1245 ci->rdomain, arg, line);
1246 } else if (strcasecmp(attrib, "version") == 0) {
1247 if (match_pattern_list(SSH_RELEASE, arg, 0) != 1)
1248 result = 0;
1249 else
1250 debug("version %.100s matched "
1251 "'version %.100s' at line %d",
1252 SSH_RELEASE, arg, line);
1253 } else {
1254 error("Unsupported Match attribute %s", oattrib);
1255 result = -1;
1256 goto out;
1257 }
1258 next:
1259 free(attrib);
1260 attrib = NULL;
1261 }
1262 if (attributes == 0) {
1263 error("One or more attributes required for Match");
1264 return -1;
1265 }
1266 out:
1267 if (ci != NULL && result != -1)
1268 debug3("match %sfound on line %d", result ? "" : "not ", line);
1269 free(attrib);
1270 return result;
1271 }
1272
1273 #define WHITESPACE " \t\r\n"
1274
1275 /* Multistate option parsing */
1276 struct multistate {
1277 char *key;
1278 int value;
1279 };
1280 static const struct multistate multistate_flag[] = {
1281 { "yes", 1 },
1282 { "no", 0 },
1283 { NULL, -1 }
1284 };
1285 static const struct multistate multistate_ignore_rhosts[] = {
1286 { "yes", IGNORE_RHOSTS_YES },
1287 { "no", IGNORE_RHOSTS_NO },
1288 { "shosts-only", IGNORE_RHOSTS_SHOSTS },
1289 { NULL, -1 }
1290 };
1291 static const struct multistate multistate_addressfamily[] = {
1292 { "inet", AF_INET },
1293 { "inet6", AF_INET6 },
1294 { "any", AF_UNSPEC },
1295 { NULL, -1 }
1296 };
1297 static const struct multistate multistate_permitrootlogin[] = {
1298 { "prohibit-password", PERMIT_NO_PASSWD },
1299 { "without-password", PERMIT_NO_PASSWD },
1300 { "forced-commands-only", PERMIT_FORCED_ONLY },
1301 { "yes", PERMIT_YES },
1302 { "no", PERMIT_NO },
1303 { NULL, -1 }
1304 };
1305 static const struct multistate multistate_compression[] = {
1306 #ifdef WITH_ZLIB
1307 { "yes", COMP_DELAYED },
1308 { "delayed", COMP_DELAYED },
1309 #endif
1310 { "no", COMP_NONE },
1311 { NULL, -1 }
1312 };
1313 static const struct multistate multistate_gatewayports[] = {
1314 { "clientspecified", 2 },
1315 { "yes", 1 },
1316 { "no", 0 },
1317 { NULL, -1 }
1318 };
1319 static const struct multistate multistate_tcpfwd[] = {
1320 { "yes", FORWARD_ALLOW },
1321 { "all", FORWARD_ALLOW },
1322 { "no", FORWARD_DENY },
1323 { "remote", FORWARD_REMOTE },
1324 { "local", FORWARD_LOCAL },
1325 { NULL, -1 }
1326 };
1327
1328 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)1329 process_server_config_line_depth(ServerOptions *options, char *line,
1330 const char *filename, int linenum, int *activep,
1331 struct connection_info *connectinfo, int *inc_flags, int depth,
1332 struct include_list *includes)
1333 {
1334 char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
1335 int cmdline = 0, *intptr, value, value2, value3, n, port, oactive, r;
1336 double dvalue, *doubleptr = NULL;
1337 int ca_only = 0, found = 0;
1338 SyslogFacility *log_facility_ptr;
1339 LogLevel *log_level_ptr;
1340 ServerOpCodes opcode;
1341 u_int i, *uintptr, flags = 0;
1342 size_t len;
1343 long long val64;
1344 const struct multistate *multistate_ptr;
1345 const char *errstr;
1346 struct include_item *item;
1347 glob_t gbuf;
1348 char **oav = NULL, **av;
1349 int oac = 0, ac;
1350 int ret = -1;
1351 char **strs = NULL; /* string array arguments; freed implicitly */
1352 u_int nstrs = 0;
1353
1354 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1355 if ((len = strlen(line)) == 0)
1356 return 0;
1357 for (len--; len > 0; len--) {
1358 if (strchr(WHITESPACE "\f", line[len]) == NULL)
1359 break;
1360 line[len] = '\0';
1361 }
1362
1363 str = line;
1364 if ((keyword = strdelim(&str)) == NULL)
1365 return 0;
1366 /* Ignore leading whitespace */
1367 if (*keyword == '\0')
1368 keyword = strdelim(&str);
1369 if (!keyword || !*keyword || *keyword == '#')
1370 return 0;
1371 if (str == NULL || *str == '\0') {
1372 error("%s line %d: no argument after keyword \"%s\"",
1373 filename, linenum, keyword);
1374 return -1;
1375 }
1376 intptr = NULL;
1377 charptr = NULL;
1378 opcode = parse_token(keyword, filename, linenum, &flags);
1379
1380 if (argv_split(str, &oac, &oav, 1) != 0) {
1381 error("%s line %d: invalid quotes", filename, linenum);
1382 return -1;
1383 }
1384 ac = oac;
1385 av = oav;
1386
1387 if (activep == NULL) { /* We are processing a command line directive */
1388 cmdline = 1;
1389 activep = &cmdline;
1390 }
1391 if (*activep && opcode != sMatch && opcode != sInclude)
1392 debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1393 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1394 if (connectinfo == NULL) {
1395 fatal("%s line %d: Directive '%s' is not allowed "
1396 "within a Match block", filename, linenum, keyword);
1397 } else { /* this is a directive we have already processed */
1398 ret = 0;
1399 goto out;
1400 }
1401 }
1402
1403 switch (opcode) {
1404 /* Portable-specific options */
1405 case sUsePAM:
1406 intptr = &options->use_pam;
1407 goto parse_flag;
1408 case sPAMServiceName:
1409 charptr = &options->pam_service_name;
1410 arg = argv_next(&ac, &av);
1411 if (!arg || *arg == '\0') {
1412 fatal("%s line %d: missing argument.",
1413 filename, linenum);
1414 }
1415 if (*activep && *charptr == NULL)
1416 *charptr = xstrdup(arg);
1417 break;
1418
1419 /* Standard Options */
1420 case sBadOption:
1421 goto out;
1422 case sPort:
1423 /* ignore ports from configfile if cmdline specifies ports */
1424 if (options->ports_from_cmdline) {
1425 argv_consume(&ac);
1426 break;
1427 }
1428 if (options->num_ports >= MAX_PORTS)
1429 fatal("%s line %d: too many ports.",
1430 filename, linenum);
1431 arg = argv_next(&ac, &av);
1432 if (!arg || *arg == '\0')
1433 fatal("%s line %d: missing port number.",
1434 filename, linenum);
1435 options->ports[options->num_ports++] = a2port(arg);
1436 if (options->ports[options->num_ports-1] <= 0)
1437 fatal("%s line %d: Badly formatted port number.",
1438 filename, linenum);
1439 break;
1440
1441 case sLoginGraceTime:
1442 intptr = &options->login_grace_time;
1443 parse_time:
1444 arg = argv_next(&ac, &av);
1445 if (!arg || *arg == '\0')
1446 fatal("%s line %d: missing time value.",
1447 filename, linenum);
1448 if ((value = convtime(arg)) == -1)
1449 fatal("%s line %d: invalid time value.",
1450 filename, linenum);
1451 if (*activep && *intptr == -1)
1452 *intptr = value;
1453 break;
1454
1455 case sListenAddress:
1456 arg = argv_next(&ac, &av);
1457 if (arg == NULL || *arg == '\0')
1458 fatal("%s line %d: missing address",
1459 filename, linenum);
1460 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
1461 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1462 && strchr(p+1, ':') != NULL) {
1463 port = 0;
1464 p = arg;
1465 } else {
1466 arg2 = NULL;
1467 p = hpdelim(&arg);
1468 if (p == NULL)
1469 fatal("%s line %d: bad address:port usage",
1470 filename, linenum);
1471 p = cleanhostname(p);
1472 if (arg == NULL)
1473 port = 0;
1474 else if ((port = a2port(arg)) <= 0)
1475 fatal("%s line %d: bad port number",
1476 filename, linenum);
1477 }
1478 /* Optional routing table */
1479 arg2 = NULL;
1480 if ((arg = argv_next(&ac, &av)) != NULL) {
1481 if (strcmp(arg, "rdomain") != 0 ||
1482 (arg2 = argv_next(&ac, &av)) == NULL)
1483 fatal("%s line %d: bad ListenAddress syntax",
1484 filename, linenum);
1485 if (!valid_rdomain(arg2))
1486 fatal("%s line %d: bad routing domain",
1487 filename, linenum);
1488 }
1489 queue_listen_addr(options, p, arg2, port);
1490
1491 break;
1492
1493 case sAddressFamily:
1494 intptr = &options->address_family;
1495 multistate_ptr = multistate_addressfamily;
1496 parse_multistate:
1497 arg = argv_next(&ac, &av);
1498 if (!arg || *arg == '\0')
1499 fatal("%s line %d: missing argument.",
1500 filename, linenum);
1501 value = -1;
1502 for (i = 0; multistate_ptr[i].key != NULL; i++) {
1503 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1504 value = multistate_ptr[i].value;
1505 break;
1506 }
1507 }
1508 if (value == -1)
1509 fatal("%s line %d: unsupported option \"%s\".",
1510 filename, linenum, arg);
1511 if (*activep && *intptr == -1)
1512 *intptr = value;
1513 break;
1514
1515 case sHostKeyFile:
1516 arg = argv_next(&ac, &av);
1517 if (!arg || *arg == '\0')
1518 fatal("%s line %d: missing file name.",
1519 filename, linenum);
1520 if (*activep) {
1521 servconf_add_hostkey(filename, linenum,
1522 options, arg, 1);
1523 }
1524 break;
1525
1526 case sHostKeyAgent:
1527 charptr = &options->host_key_agent;
1528 arg = argv_next(&ac, &av);
1529 if (!arg || *arg == '\0')
1530 fatal("%s line %d: missing socket name.",
1531 filename, linenum);
1532 if (*activep && *charptr == NULL)
1533 *charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1534 xstrdup(arg) : derelativise_path(arg);
1535 break;
1536
1537 case sHostCertificate:
1538 arg = argv_next(&ac, &av);
1539 if (!arg || *arg == '\0')
1540 fatal("%s line %d: missing file name.",
1541 filename, linenum);
1542 if (*activep)
1543 servconf_add_hostcert(filename, linenum, options, arg);
1544 break;
1545
1546 case sPidFile:
1547 charptr = &options->pid_file;
1548 parse_filename:
1549 arg = argv_next(&ac, &av);
1550 if (!arg || *arg == '\0')
1551 fatal("%s line %d: missing file name.",
1552 filename, linenum);
1553 if (*activep && *charptr == NULL) {
1554 *charptr = derelativise_path(arg);
1555 /* increase optional counter */
1556 if (intptr != NULL)
1557 *intptr = *intptr + 1;
1558 }
1559 break;
1560
1561 case sModuliFile:
1562 charptr = &options->moduli_file;
1563 goto parse_filename;
1564
1565 case sPermitRootLogin:
1566 intptr = &options->permit_root_login;
1567 multistate_ptr = multistate_permitrootlogin;
1568 goto parse_multistate;
1569
1570 case sIgnoreRhosts:
1571 intptr = &options->ignore_rhosts;
1572 multistate_ptr = multistate_ignore_rhosts;
1573 goto parse_multistate;
1574
1575 case sIgnoreUserKnownHosts:
1576 intptr = &options->ignore_user_known_hosts;
1577 parse_flag:
1578 multistate_ptr = multistate_flag;
1579 goto parse_multistate;
1580
1581 case sHostbasedAuthentication:
1582 intptr = &options->hostbased_authentication;
1583 goto parse_flag;
1584
1585 case sHostbasedUsesNameFromPacketOnly:
1586 intptr = &options->hostbased_uses_name_from_packet_only;
1587 goto parse_flag;
1588
1589 case sHostbasedAcceptedAlgorithms:
1590 charptr = &options->hostbased_accepted_algos;
1591 ca_only = 0;
1592 parse_pubkey_algos:
1593 arg = argv_next(&ac, &av);
1594 if (!arg || *arg == '\0')
1595 fatal("%s line %d: Missing argument.",
1596 filename, linenum);
1597 if (*arg != '-' &&
1598 !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1599 arg + 1 : arg, 1, ca_only))
1600 fatal("%s line %d: Bad key types '%s'.",
1601 filename, linenum, arg ? arg : "<NONE>");
1602 if (*activep && *charptr == NULL)
1603 *charptr = xstrdup(arg);
1604 break;
1605
1606 case sHostKeyAlgorithms:
1607 charptr = &options->hostkeyalgorithms;
1608 ca_only = 0;
1609 goto parse_pubkey_algos;
1610
1611 case sCASignatureAlgorithms:
1612 charptr = &options->ca_sign_algorithms;
1613 ca_only = 1;
1614 goto parse_pubkey_algos;
1615
1616 case sPubkeyAuthentication:
1617 intptr = &options->pubkey_authentication;
1618 ca_only = 0;
1619 goto parse_flag;
1620
1621 case sPubkeyAcceptedAlgorithms:
1622 charptr = &options->pubkey_accepted_algos;
1623 ca_only = 0;
1624 goto parse_pubkey_algos;
1625
1626 case sPubkeyAuthOptions:
1627 intptr = &options->pubkey_auth_options;
1628 value = 0;
1629 while ((arg = argv_next(&ac, &av)) != NULL) {
1630 if (strcasecmp(arg, "none") == 0)
1631 continue;
1632 if (strcasecmp(arg, "touch-required") == 0)
1633 value |= PUBKEYAUTH_TOUCH_REQUIRED;
1634 else if (strcasecmp(arg, "verify-required") == 0)
1635 value |= PUBKEYAUTH_VERIFY_REQUIRED;
1636 else {
1637 error("%s line %d: unsupported %s option %s",
1638 filename, linenum, keyword, arg);
1639 goto out;
1640 }
1641 }
1642 if (*activep && *intptr == -1)
1643 *intptr = value;
1644 break;
1645
1646 case sKerberosAuthentication:
1647 intptr = &options->kerberos_authentication;
1648 goto parse_flag;
1649
1650 case sKerberosOrLocalPasswd:
1651 intptr = &options->kerberos_or_local_passwd;
1652 goto parse_flag;
1653
1654 case sKerberosTicketCleanup:
1655 intptr = &options->kerberos_ticket_cleanup;
1656 goto parse_flag;
1657
1658 case sKerberosGetAFSToken:
1659 intptr = &options->kerberos_get_afs_token;
1660 goto parse_flag;
1661
1662 case sGssAuthentication:
1663 intptr = &options->gss_authentication;
1664 goto parse_flag;
1665
1666 case sGssCleanupCreds:
1667 intptr = &options->gss_cleanup_creds;
1668 goto parse_flag;
1669
1670 case sGssDelegateCreds:
1671 intptr = &options->gss_deleg_creds;
1672 goto parse_flag;
1673
1674 case sGssStrictAcceptor:
1675 intptr = &options->gss_strict_acceptor;
1676 goto parse_flag;
1677
1678 case sPasswordAuthentication:
1679 intptr = &options->password_authentication;
1680 goto parse_flag;
1681
1682 case sKbdInteractiveAuthentication:
1683 intptr = &options->kbd_interactive_authentication;
1684 goto parse_flag;
1685
1686 case sPrintMotd:
1687 intptr = &options->print_motd;
1688 goto parse_flag;
1689
1690 case sPrintLastLog:
1691 intptr = &options->print_lastlog;
1692 goto parse_flag;
1693
1694 case sX11Forwarding:
1695 intptr = &options->x11_forwarding;
1696 goto parse_flag;
1697
1698 case sX11DisplayOffset:
1699 intptr = &options->x11_display_offset;
1700 parse_int:
1701 arg = argv_next(&ac, &av);
1702 if ((errstr = atoi_err(arg, &value)) != NULL)
1703 fatal("%s line %d: %s integer value %s.",
1704 filename, linenum, keyword, errstr);
1705 if (*activep && *intptr == -1)
1706 *intptr = value;
1707 break;
1708
1709 case sX11UseLocalhost:
1710 intptr = &options->x11_use_localhost;
1711 goto parse_flag;
1712
1713 case sXAuthLocation:
1714 charptr = &options->xauth_location;
1715 goto parse_filename;
1716
1717 case sPermitTTY:
1718 intptr = &options->permit_tty;
1719 goto parse_flag;
1720
1721 case sPermitUserRC:
1722 intptr = &options->permit_user_rc;
1723 goto parse_flag;
1724
1725 case sStrictModes:
1726 intptr = &options->strict_modes;
1727 goto parse_flag;
1728
1729 case sTCPKeepAlive:
1730 intptr = &options->tcp_keep_alive;
1731 goto parse_flag;
1732
1733 case sEmptyPasswd:
1734 intptr = &options->permit_empty_passwd;
1735 goto parse_flag;
1736
1737 case sPermitUserEnvironment:
1738 intptr = &options->permit_user_env;
1739 charptr = &options->permit_user_env_allowlist;
1740 arg = argv_next(&ac, &av);
1741 if (!arg || *arg == '\0')
1742 fatal("%s line %d: %s missing argument.",
1743 filename, linenum, keyword);
1744 value = 0;
1745 p = NULL;
1746 if (strcmp(arg, "yes") == 0)
1747 value = 1;
1748 else if (strcmp(arg, "no") == 0)
1749 value = 0;
1750 else {
1751 /* Pattern-list specified */
1752 value = 1;
1753 p = xstrdup(arg);
1754 }
1755 if (*activep && *intptr == -1) {
1756 *intptr = value;
1757 *charptr = p;
1758 p = NULL;
1759 }
1760 free(p);
1761 break;
1762
1763 case sCompression:
1764 intptr = &options->compression;
1765 multistate_ptr = multistate_compression;
1766 goto parse_multistate;
1767
1768 case sRekeyLimit:
1769 arg = argv_next(&ac, &av);
1770 if (!arg || *arg == '\0')
1771 fatal("%s line %d: %s missing argument.",
1772 filename, linenum, keyword);
1773 if (strcmp(arg, "default") == 0) {
1774 val64 = 0;
1775 } else {
1776 if (scan_scaled(arg, &val64) == -1)
1777 fatal("%.200s line %d: Bad %s number '%s': %s",
1778 filename, linenum, keyword,
1779 arg, strerror(errno));
1780 if (val64 != 0 && val64 < 16)
1781 fatal("%.200s line %d: %s too small",
1782 filename, linenum, keyword);
1783 }
1784 if (*activep && options->rekey_limit == -1)
1785 options->rekey_limit = val64;
1786 if (ac != 0) { /* optional rekey interval present */
1787 if (strcmp(av[0], "none") == 0) {
1788 (void)argv_next(&ac, &av); /* discard */
1789 break;
1790 }
1791 intptr = &options->rekey_interval;
1792 goto parse_time;
1793 }
1794 break;
1795
1796 case sGatewayPorts:
1797 intptr = &options->fwd_opts.gateway_ports;
1798 multistate_ptr = multistate_gatewayports;
1799 goto parse_multistate;
1800
1801 case sUseDNS:
1802 intptr = &options->use_dns;
1803 goto parse_flag;
1804
1805 case sLogFacility:
1806 log_facility_ptr = &options->log_facility;
1807 arg = argv_next(&ac, &av);
1808 value = log_facility_number(arg);
1809 if (value == SYSLOG_FACILITY_NOT_SET)
1810 fatal("%.200s line %d: unsupported log facility '%s'",
1811 filename, linenum, arg ? arg : "<NONE>");
1812 if (*log_facility_ptr == -1)
1813 *log_facility_ptr = (SyslogFacility) value;
1814 break;
1815
1816 case sLogLevel:
1817 log_level_ptr = &options->log_level;
1818 arg = argv_next(&ac, &av);
1819 value = log_level_number(arg);
1820 if (value == SYSLOG_LEVEL_NOT_SET)
1821 fatal("%.200s line %d: unsupported log level '%s'",
1822 filename, linenum, arg ? arg : "<NONE>");
1823 if (*activep && *log_level_ptr == -1)
1824 *log_level_ptr = (LogLevel) value;
1825 break;
1826
1827 case sLogVerbose:
1828 found = options->num_log_verbose == 0;
1829 while ((arg = argv_next(&ac, &av)) != NULL) {
1830 if (*arg == '\0') {
1831 error("%s line %d: keyword %s empty argument",
1832 filename, linenum, keyword);
1833 goto out;
1834 }
1835 /* Allow "none" only in first position */
1836 if (strcasecmp(arg, "none") == 0) {
1837 if (nstrs > 0 || ac > 0) {
1838 error("%s line %d: keyword %s \"none\" "
1839 "argument must appear alone.",
1840 filename, linenum, keyword);
1841 goto out;
1842 }
1843 }
1844 opt_array_append(filename, linenum, keyword,
1845 &strs, &nstrs, arg);
1846 }
1847 if (nstrs == 0) {
1848 fatal("%s line %d: no %s specified",
1849 filename, linenum, keyword);
1850 }
1851 if (found && *activep) {
1852 options->log_verbose = strs;
1853 options->num_log_verbose = nstrs;
1854 strs = NULL; /* transferred */
1855 nstrs = 0;
1856 }
1857 break;
1858
1859 case sAllowTcpForwarding:
1860 intptr = &options->allow_tcp_forwarding;
1861 multistate_ptr = multistate_tcpfwd;
1862 goto parse_multistate;
1863
1864 case sAllowStreamLocalForwarding:
1865 intptr = &options->allow_streamlocal_forwarding;
1866 multistate_ptr = multistate_tcpfwd;
1867 goto parse_multistate;
1868
1869 case sAllowAgentForwarding:
1870 intptr = &options->allow_agent_forwarding;
1871 goto parse_flag;
1872
1873 case sDisableForwarding:
1874 intptr = &options->disable_forwarding;
1875 goto parse_flag;
1876
1877 case sAllowUsers:
1878 chararrayptr = &options->allow_users;
1879 uintptr = &options->num_allow_users;
1880 parse_allowdenyusers:
1881 /* XXX appends to list; doesn't respect first-match-wins */
1882 while ((arg = argv_next(&ac, &av)) != NULL) {
1883 if (*arg == '\0' ||
1884 match_user(NULL, NULL, NULL, arg) == -1)
1885 fatal("%s line %d: invalid %s pattern: \"%s\"",
1886 filename, linenum, keyword, arg);
1887 found = 1;
1888 if (!*activep)
1889 continue;
1890 opt_array_append(filename, linenum, keyword,
1891 chararrayptr, uintptr, arg);
1892 }
1893 if (!found) {
1894 fatal("%s line %d: no %s specified",
1895 filename, linenum, keyword);
1896 }
1897 break;
1898
1899 case sDenyUsers:
1900 chararrayptr = &options->deny_users;
1901 uintptr = &options->num_deny_users;
1902 goto parse_allowdenyusers;
1903
1904 case sAllowGroups:
1905 chararrayptr = &options->allow_groups;
1906 uintptr = &options->num_allow_groups;
1907 /* XXX appends to list; doesn't respect first-match-wins */
1908 parse_allowdenygroups:
1909 while ((arg = argv_next(&ac, &av)) != NULL) {
1910 if (*arg == '\0')
1911 fatal("%s line %d: empty %s pattern",
1912 filename, linenum, keyword);
1913 found = 1;
1914 if (!*activep)
1915 continue;
1916 opt_array_append(filename, linenum, keyword,
1917 chararrayptr, uintptr, arg);
1918 }
1919 if (!found) {
1920 fatal("%s line %d: no %s specified",
1921 filename, linenum, keyword);
1922 }
1923 break;
1924
1925 case sDenyGroups:
1926 chararrayptr = &options->deny_groups;
1927 uintptr = &options->num_deny_groups;
1928 goto parse_allowdenygroups;
1929
1930 case sCiphers:
1931 arg = argv_next(&ac, &av);
1932 if (!arg || *arg == '\0')
1933 fatal("%s line %d: %s missing argument.",
1934 filename, linenum, keyword);
1935 if (*arg != '-' &&
1936 !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1937 fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1938 filename, linenum, arg ? arg : "<NONE>");
1939 if (options->ciphers == NULL)
1940 options->ciphers = xstrdup(arg);
1941 break;
1942
1943 case sMacs:
1944 arg = argv_next(&ac, &av);
1945 if (!arg || *arg == '\0')
1946 fatal("%s line %d: %s missing argument.",
1947 filename, linenum, keyword);
1948 if (*arg != '-' &&
1949 !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1950 fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1951 filename, linenum, arg ? arg : "<NONE>");
1952 if (options->macs == NULL)
1953 options->macs = xstrdup(arg);
1954 break;
1955
1956 case sKexAlgorithms:
1957 arg = argv_next(&ac, &av);
1958 if (!arg || *arg == '\0')
1959 fatal("%s line %d: %s missing argument.",
1960 filename, linenum, keyword);
1961 if (*arg != '-' &&
1962 !kex_names_valid(*arg == '+' || *arg == '^' ?
1963 arg + 1 : arg))
1964 fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
1965 filename, linenum, arg ? arg : "<NONE>");
1966 if (options->kex_algorithms == NULL)
1967 options->kex_algorithms = xstrdup(arg);
1968 break;
1969
1970 case sSubsystem:
1971 if ((arg = argv_next(&ac, &av)) == NULL || *arg == '\0' ||
1972 ((arg2 = argv_next(&ac, &av)) == NULL || *arg2 == '\0'))
1973 fatal("%s line %d: %s missing argument.",
1974 filename, linenum, keyword);
1975 if (!*activep) {
1976 argv_consume(&ac);
1977 break;
1978 }
1979 found = 0;
1980 for (i = 0; i < options->num_subsystems; i++) {
1981 if (strcmp(arg, options->subsystem_name[i]) == 0) {
1982 found = 1;
1983 break;
1984 }
1985 }
1986 if (found) {
1987 debug("%s line %d: Subsystem '%s' already defined.",
1988 filename, linenum, arg);
1989 argv_consume(&ac);
1990 break;
1991 }
1992 options->subsystem_name = xrecallocarray(
1993 options->subsystem_name, options->num_subsystems,
1994 options->num_subsystems + 1,
1995 sizeof(*options->subsystem_name));
1996 options->subsystem_command = xrecallocarray(
1997 options->subsystem_command, options->num_subsystems,
1998 options->num_subsystems + 1,
1999 sizeof(*options->subsystem_command));
2000 options->subsystem_args = xrecallocarray(
2001 options->subsystem_args, options->num_subsystems,
2002 options->num_subsystems + 1,
2003 sizeof(*options->subsystem_args));
2004 options->subsystem_name[options->num_subsystems] = xstrdup(arg);
2005 options->subsystem_command[options->num_subsystems] =
2006 xstrdup(arg2);
2007 /* Collect arguments (separate to executable) */
2008 arg = argv_assemble(1, &arg2); /* quote command correctly */
2009 arg2 = argv_assemble(ac, av); /* rest of command */
2010 xasprintf(&options->subsystem_args[options->num_subsystems],
2011 "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2);
2012 free(arg2);
2013 free(arg);
2014 argv_consume(&ac);
2015 options->num_subsystems++;
2016 break;
2017
2018 case sMaxStartups:
2019 arg = argv_next(&ac, &av);
2020 if (!arg || *arg == '\0')
2021 fatal("%s line %d: %s missing argument.",
2022 filename, linenum, keyword);
2023 /* begin:rate:max */
2024 if ((n = sscanf(arg, "%d:%d:%d",
2025 &value, &value2, &value3)) == 3) {
2026 if (value > value3 || value2 > 100 || value2 < 1)
2027 fatal("%s line %d: Invalid %s spec.",
2028 filename, linenum, keyword);
2029 } else if (n == 1) {
2030 value3 = value;
2031 value2 = -1;
2032 } else {
2033 fatal("%s line %d: Invalid %s spec.",
2034 filename, linenum, keyword);
2035 }
2036 if (value <= 0 || value3 <= 0)
2037 fatal("%s line %d: Invalid %s spec.",
2038 filename, linenum, keyword);
2039 if (*activep && options->max_startups == -1) {
2040 options->max_startups_begin = value;
2041 options->max_startups_rate = value2;
2042 options->max_startups = value3;
2043 }
2044 break;
2045
2046 case sPerSourceNetBlockSize:
2047 arg = argv_next(&ac, &av);
2048 if (!arg || *arg == '\0')
2049 fatal("%s line %d: %s missing argument.",
2050 filename, linenum, keyword);
2051 switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
2052 case 2:
2053 if (value2 < 0 || value2 > 128)
2054 n = -1;
2055 /* FALLTHROUGH */
2056 case 1:
2057 if (value < 0 || value > 32)
2058 n = -1;
2059 }
2060 if (n != 1 && n != 2)
2061 fatal("%s line %d: Invalid %s spec.",
2062 filename, linenum, keyword);
2063 if (*activep && options->per_source_masklen_ipv4 == -1) {
2064 options->per_source_masklen_ipv4 = value;
2065 if (n == 2)
2066 options->per_source_masklen_ipv6 = value2;
2067 }
2068 break;
2069
2070 case sPerSourceMaxStartups:
2071 arg = argv_next(&ac, &av);
2072 if (!arg || *arg == '\0')
2073 fatal("%s line %d: %s missing argument.",
2074 filename, linenum, keyword);
2075 if (strcmp(arg, "none") == 0) { /* no limit */
2076 value = INT_MAX;
2077 } else {
2078 if ((errstr = atoi_err(arg, &value)) != NULL)
2079 fatal("%s line %d: %s integer value %s.",
2080 filename, linenum, keyword, errstr);
2081 }
2082 if (*activep && options->per_source_max_startups == -1)
2083 options->per_source_max_startups = value;
2084 break;
2085
2086 case sPerSourcePenaltyExemptList:
2087 charptr = &options->per_source_penalty_exempt;
2088 arg = argv_next(&ac, &av);
2089 if (!arg || *arg == '\0')
2090 fatal("%s line %d: missing argument.",
2091 filename, linenum);
2092 if (addr_match_list(NULL, arg) != 0) {
2093 fatal("%s line %d: keyword %s "
2094 "invalid address argument.",
2095 filename, linenum, keyword);
2096 }
2097 if (*activep && *charptr == NULL)
2098 *charptr = xstrdup(arg);
2099 break;
2100
2101 case sPerSourcePenalties:
2102 while ((arg = argv_next(&ac, &av)) != NULL) {
2103 const char *q = NULL;
2104
2105 found = 1;
2106 intptr = NULL;
2107 doubleptr = NULL;
2108 value = -1;
2109 value2 = 0;
2110 /* Allow no/yes only in first position */
2111 if (strcasecmp(arg, "no") == 0 ||
2112 (value2 = (strcasecmp(arg, "yes") == 0))) {
2113 if (ac > 0) {
2114 fatal("%s line %d: keyword %s \"%s\" "
2115 "argument must appear alone.",
2116 filename, linenum, keyword, arg);
2117 }
2118 if (*activep &&
2119 options->per_source_penalty.enabled == -1)
2120 options->per_source_penalty.enabled = value2;
2121 continue;
2122 } else if ((q = strprefix(arg, "crash:", 0)) != NULL) {
2123 doubleptr = &options->per_source_penalty.penalty_crash;
2124 } else if ((q = strprefix(arg, "authfail:", 0)) != NULL) {
2125 doubleptr = &options->per_source_penalty.penalty_authfail;
2126 } else if ((q = strprefix(arg, "invaliduser:", 0)) != NULL) {
2127 doubleptr = &options->per_source_penalty.penalty_invaliduser;
2128 } else if ((q = strprefix(arg, "noauth:", 0)) != NULL) {
2129 doubleptr = &options->per_source_penalty.penalty_noauth;
2130 } else if ((q = strprefix(arg, "grace-exceeded:", 0)) != NULL) {
2131 doubleptr = &options->per_source_penalty.penalty_grace;
2132 } else if ((q = strprefix(arg, "refuseconnection:", 0)) != NULL) {
2133 doubleptr = &options->per_source_penalty.penalty_refuseconnection;
2134 } else if ((q = strprefix(arg, "max:", 0)) != NULL) {
2135 doubleptr = &options->per_source_penalty.penalty_max;
2136 } else if ((q = strprefix(arg, "min:", 0)) != NULL) {
2137 doubleptr = &options->per_source_penalty.penalty_min;
2138 } else if ((q = strprefix(arg, "max-sources4:", 0)) != NULL) {
2139 intptr = &options->per_source_penalty.max_sources4;
2140 if ((errstr = atoi_err(q, &value)) != NULL)
2141 fatal("%s line %d: %s value %s.",
2142 filename, linenum, keyword, errstr);
2143 } else if ((q = strprefix(arg, "max-sources6:", 0)) != NULL) {
2144 intptr = &options->per_source_penalty.max_sources6;
2145 if ((errstr = atoi_err(q, &value)) != NULL)
2146 fatal("%s line %d: %s value %s.",
2147 filename, linenum, keyword, errstr);
2148 } else if (strcmp(arg, "overflow:deny-all") == 0) {
2149 intptr = &options->per_source_penalty.overflow_mode;
2150 value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
2151 } else if (strcmp(arg, "overflow:permissive") == 0) {
2152 intptr = &options->per_source_penalty.overflow_mode;
2153 value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
2154 } else if (strcmp(arg, "overflow6:deny-all") == 0) {
2155 intptr = &options->per_source_penalty.overflow_mode6;
2156 value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
2157 } else if (strcmp(arg, "overflow6:permissive") == 0) {
2158 intptr = &options->per_source_penalty.overflow_mode6;
2159 value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
2160 } else {
2161 fatal("%s line %d: unsupported %s keyword %s",
2162 filename, linenum, keyword, arg);
2163 }
2164
2165 if (doubleptr != NULL) {
2166 if ((dvalue = convtime_double(q)) < 0) {
2167 fatal("%s line %d: invalid %s time value.",
2168 filename, linenum, keyword);
2169 }
2170 if (*activep && *doubleptr < 0.0) {
2171 *doubleptr = dvalue;
2172 options->per_source_penalty.enabled = 1;
2173 }
2174 } else if (intptr != NULL) {
2175 if (*activep && *intptr == -1) {
2176 *intptr = value;
2177 options->per_source_penalty.enabled = 1;
2178 }
2179 } else {
2180 fatal_f("%s line %d: internal error",
2181 filename, linenum);
2182 }
2183 }
2184 if (!found) {
2185 fatal("%s line %d: no %s specified",
2186 filename, linenum, keyword);
2187 }
2188 break;
2189
2190 case sMaxAuthTries:
2191 intptr = &options->max_authtries;
2192 goto parse_int;
2193
2194 case sMaxSessions:
2195 intptr = &options->max_sessions;
2196 goto parse_int;
2197
2198 case sBanner:
2199 charptr = &options->banner;
2200 goto parse_filename;
2201
2202 /*
2203 * These options can contain %X options expanded at
2204 * connect time, so that you can specify paths like:
2205 *
2206 * AuthorizedKeysFile /etc/ssh_keys/%u
2207 */
2208 case sAuthorizedKeysFile:
2209 uintptr = &options->num_authkeys_files;
2210 chararrayptr = &options->authorized_keys_files;
2211 parse_filenames:
2212 found = *uintptr == 0;
2213 while ((arg = argv_next(&ac, &av)) != NULL) {
2214 if (*arg == '\0') {
2215 error("%s line %d: keyword %s empty argument",
2216 filename, linenum, keyword);
2217 goto out;
2218 }
2219 /* Allow "none" only in first position */
2220 if (strcasecmp(arg, "none") == 0) {
2221 if (nstrs > 0 || ac > 0) {
2222 error("%s line %d: keyword %s \"none\" "
2223 "argument must appear alone.",
2224 filename, linenum, keyword);
2225 goto out;
2226 }
2227 }
2228 arg2 = tilde_expand_filename(arg, getuid());
2229 opt_array_append(filename, linenum, keyword,
2230 &strs, &nstrs, arg2);
2231 free(arg2);
2232 }
2233 if (nstrs == 0) {
2234 fatal("%s line %d: no %s specified",
2235 filename, linenum, keyword);
2236 }
2237 if (found && *activep) {
2238 *chararrayptr = strs;
2239 *uintptr = nstrs;
2240 strs = NULL; /* transferred */
2241 nstrs = 0;
2242 }
2243 break;
2244
2245 case sAuthorizedPrincipalsFile:
2246 charptr = &options->authorized_principals_file;
2247 arg = argv_next(&ac, &av);
2248 if (!arg || *arg == '\0')
2249 fatal("%s line %d: %s missing argument.",
2250 filename, linenum, keyword);
2251 if (*activep && *charptr == NULL) {
2252 *charptr = tilde_expand_filename(arg, getuid());
2253 /* increase optional counter */
2254 if (intptr != NULL)
2255 *intptr = *intptr + 1;
2256 }
2257 break;
2258
2259 case sClientAliveInterval:
2260 intptr = &options->client_alive_interval;
2261 goto parse_time;
2262
2263 case sClientAliveCountMax:
2264 intptr = &options->client_alive_count_max;
2265 goto parse_int;
2266
2267 case sAcceptEnv:
2268 /* XXX appends to list; doesn't respect first-match-wins */
2269 while ((arg = argv_next(&ac, &av)) != NULL) {
2270 if (*arg == '\0' || strchr(arg, '=') != NULL)
2271 fatal("%s line %d: Invalid environment name.",
2272 filename, linenum);
2273 found = 1;
2274 if (!*activep)
2275 continue;
2276 opt_array_append(filename, linenum, keyword,
2277 &options->accept_env, &options->num_accept_env,
2278 arg);
2279 }
2280 if (!found) {
2281 fatal("%s line %d: no %s specified",
2282 filename, linenum, keyword);
2283 }
2284 break;
2285
2286 case sSetEnv:
2287 found = options->num_setenv == 0;
2288 while ((arg = argv_next(&ac, &av)) != NULL) {
2289 if (*arg == '\0' || strchr(arg, '=') == NULL)
2290 fatal("%s line %d: Invalid environment.",
2291 filename, linenum);
2292 if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
2293 debug2("%s line %d: ignoring duplicate env "
2294 "name \"%.64s\"", filename, linenum, arg);
2295 continue;
2296 }
2297 opt_array_append(filename, linenum, keyword,
2298 &strs, &nstrs, arg);
2299 }
2300 if (nstrs == 0) {
2301 fatal("%s line %d: no %s specified",
2302 filename, linenum, keyword);
2303 }
2304 if (found && *activep) {
2305 options->setenv = strs;
2306 options->num_setenv = nstrs;
2307 strs = NULL; /* transferred */
2308 nstrs = 0;
2309 }
2310 break;
2311
2312 case sPermitTunnel:
2313 intptr = &options->permit_tun;
2314 arg = argv_next(&ac, &av);
2315 if (!arg || *arg == '\0')
2316 fatal("%s line %d: %s missing argument.",
2317 filename, linenum, keyword);
2318 value = -1;
2319 for (i = 0; tunmode_desc[i].val != -1; i++)
2320 if (strcmp(tunmode_desc[i].text, arg) == 0) {
2321 value = tunmode_desc[i].val;
2322 break;
2323 }
2324 if (value == -1)
2325 fatal("%s line %d: bad %s argument %s",
2326 filename, linenum, keyword, arg);
2327 if (*activep && *intptr == -1)
2328 *intptr = value;
2329 break;
2330
2331 case sInclude:
2332 if (cmdline) {
2333 fatal("Include directive not supported as a "
2334 "command-line option");
2335 }
2336 value = 0;
2337 while ((arg2 = argv_next(&ac, &av)) != NULL) {
2338 if (*arg2 == '\0') {
2339 error("%s line %d: keyword %s empty argument",
2340 filename, linenum, keyword);
2341 goto out;
2342 }
2343 value++;
2344 found = 0;
2345 if (*arg2 != '/' && *arg2 != '~') {
2346 xasprintf(&arg, "%s/%s", SSHDIR, arg2);
2347 } else
2348 arg = xstrdup(arg2);
2349
2350 /*
2351 * Don't let included files clobber the containing
2352 * file's Match state.
2353 */
2354 oactive = *activep;
2355
2356 /* consult cache of include files */
2357 TAILQ_FOREACH(item, includes, entry) {
2358 if (strcmp(item->selector, arg) != 0)
2359 continue;
2360 if (item->filename != NULL) {
2361 parse_server_config_depth(options,
2362 item->filename, item->contents,
2363 includes, connectinfo,
2364 (*inc_flags & SSHCFG_MATCH_ONLY
2365 ? SSHCFG_MATCH_ONLY : (oactive
2366 ? 0 : SSHCFG_NEVERMATCH)),
2367 activep, depth + 1);
2368 }
2369 found = 1;
2370 *activep = oactive;
2371 }
2372 if (found != 0) {
2373 free(arg);
2374 continue;
2375 }
2376
2377 /* requested glob was not in cache */
2378 debug2("%s line %d: new include %s",
2379 filename, linenum, arg);
2380 if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
2381 if (r != GLOB_NOMATCH) {
2382 fatal("%s line %d: include \"%s\" glob "
2383 "failed", filename, linenum, arg);
2384 }
2385 /*
2386 * If no entry matched then record a
2387 * placeholder to skip later glob calls.
2388 */
2389 debug2("%s line %d: no match for %s",
2390 filename, linenum, arg);
2391 item = xcalloc(1, sizeof(*item));
2392 item->selector = strdup(arg);
2393 TAILQ_INSERT_TAIL(includes,
2394 item, entry);
2395 }
2396 if (gbuf.gl_pathc > INT_MAX)
2397 fatal_f("too many glob results");
2398 for (n = 0; n < (int)gbuf.gl_pathc; n++) {
2399 debug2("%s line %d: including %s",
2400 filename, linenum, gbuf.gl_pathv[n]);
2401 item = xcalloc(1, sizeof(*item));
2402 item->selector = strdup(arg);
2403 item->filename = strdup(gbuf.gl_pathv[n]);
2404 if ((item->contents = sshbuf_new()) == NULL)
2405 fatal_f("sshbuf_new failed");
2406 load_server_config(item->filename,
2407 item->contents);
2408 parse_server_config_depth(options,
2409 item->filename, item->contents,
2410 includes, connectinfo,
2411 (*inc_flags & SSHCFG_MATCH_ONLY
2412 ? SSHCFG_MATCH_ONLY : (oactive
2413 ? 0 : SSHCFG_NEVERMATCH)),
2414 activep, depth + 1);
2415 *activep = oactive;
2416 TAILQ_INSERT_TAIL(includes, item, entry);
2417 }
2418 globfree(&gbuf);
2419 free(arg);
2420 }
2421 if (value == 0) {
2422 fatal("%s line %d: %s missing filename argument",
2423 filename, linenum, keyword);
2424 }
2425 break;
2426
2427 case sMatch:
2428 if (cmdline)
2429 fatal("Match directive not supported as a command-line "
2430 "option");
2431 value = match_cfg_line(str, &ac, &av, linenum,
2432 (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2433 if (value < 0)
2434 fatal("%s line %d: Bad Match condition", filename,
2435 linenum);
2436 *activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
2437 /*
2438 * The MATCH_ONLY flag is applicable only until the first
2439 * match block.
2440 */
2441 *inc_flags &= ~SSHCFG_MATCH_ONLY;
2442 break;
2443
2444 case sPermitListen:
2445 case sPermitOpen:
2446 if (opcode == sPermitListen) {
2447 uintptr = &options->num_permitted_listens;
2448 chararrayptr = &options->permitted_listens;
2449 } else {
2450 uintptr = &options->num_permitted_opens;
2451 chararrayptr = &options->permitted_opens;
2452 }
2453 found = *uintptr == 0;
2454 while ((arg = argv_next(&ac, &av)) != NULL) {
2455 if (strcmp(arg, "any") == 0 ||
2456 strcmp(arg, "none") == 0) {
2457 if (nstrs != 0) {
2458 fatal("%s line %d: %s must appear "
2459 "alone on a %s line.",
2460 filename, linenum, arg, keyword);
2461 }
2462 opt_array_append(filename, linenum, keyword,
2463 &strs, &nstrs, arg);
2464 continue;
2465 }
2466
2467 if (opcode == sPermitListen &&
2468 strchr(arg, ':') == NULL) {
2469 /*
2470 * Allow bare port number for PermitListen
2471 * to indicate a wildcard listen host.
2472 */
2473 xasprintf(&arg2, "*:%s", arg);
2474 } else {
2475 arg2 = xstrdup(arg);
2476 p = hpdelim(&arg);
2477 if (p == NULL) {
2478 fatal("%s line %d: %s missing host",
2479 filename, linenum, keyword);
2480 }
2481 p = cleanhostname(p);
2482 }
2483 if (arg == NULL ||
2484 ((port = permitopen_port(arg)) < 0)) {
2485 fatal("%s line %d: %s bad port number",
2486 filename, linenum, keyword);
2487 }
2488 opt_array_append(filename, linenum, keyword,
2489 &strs, &nstrs, arg2);
2490 free(arg2);
2491 }
2492 if (nstrs == 0) {
2493 fatal("%s line %d: %s missing argument.",
2494 filename, linenum, keyword);
2495 }
2496 if (found && *activep) {
2497 *chararrayptr = strs;
2498 *uintptr = nstrs;
2499 strs = NULL; /* transferred */
2500 nstrs = 0;
2501 }
2502 break;
2503
2504 case sForceCommand:
2505 if (str == NULL || *str == '\0')
2506 fatal("%s line %d: %s missing argument.",
2507 filename, linenum, keyword);
2508 len = strspn(str, WHITESPACE);
2509 if (*activep && options->adm_forced_command == NULL)
2510 options->adm_forced_command = xstrdup(str + len);
2511 argv_consume(&ac);
2512 break;
2513
2514 case sChrootDirectory:
2515 charptr = &options->chroot_directory;
2516
2517 arg = argv_next(&ac, &av);
2518 if (!arg || *arg == '\0')
2519 fatal("%s line %d: %s missing argument.",
2520 filename, linenum, keyword);
2521 if (*activep && *charptr == NULL)
2522 *charptr = xstrdup(arg);
2523 break;
2524
2525 case sTrustedUserCAKeys:
2526 charptr = &options->trusted_user_ca_keys;
2527 goto parse_filename;
2528
2529 case sRevokedKeys:
2530 uintptr = &options->num_revoked_keys_files;
2531 chararrayptr = &options->revoked_keys_files;
2532 goto parse_filenames;
2533
2534 case sSecurityKeyProvider:
2535 charptr = &options->sk_provider;
2536 arg = argv_next(&ac, &av);
2537 if (!arg || *arg == '\0')
2538 fatal("%s line %d: %s missing argument.",
2539 filename, linenum, keyword);
2540 if (*activep && *charptr == NULL) {
2541 *charptr = strcasecmp(arg, "internal") == 0 ?
2542 xstrdup(arg) : derelativise_path(arg);
2543 /* increase optional counter */
2544 if (intptr != NULL)
2545 *intptr = *intptr + 1;
2546 }
2547 break;
2548
2549 case sIPQoS:
2550 arg = argv_next(&ac, &av);
2551 if (!arg || *arg == '\0')
2552 fatal("%s line %d: %s missing argument.",
2553 filename, linenum, keyword);
2554 if ((value = parse_ipqos(arg)) == -1)
2555 fatal("%s line %d: Bad %s value: %s",
2556 filename, linenum, keyword, arg);
2557 if (value == INT_MIN) {
2558 debug("%s line %d: Deprecated IPQoS value \"%s\" "
2559 "ignored - using system default instead. Consider"
2560 " using DSCP values.", filename, linenum, arg);
2561 value = INT_MAX;
2562 }
2563 arg = argv_next(&ac, &av);
2564 if (arg == NULL)
2565 value2 = value;
2566 else if ((value2 = parse_ipqos(arg)) == -1)
2567 fatal("%s line %d: Bad %s value: %s",
2568 filename, linenum, keyword, arg);
2569 if (value2 == INT_MIN) {
2570 debug("%s line %d: Deprecated IPQoS value \"%s\" "
2571 "ignored - using system default instead. Consider"
2572 " using DSCP values.", filename, linenum, arg);
2573 value2 = INT_MAX;
2574 }
2575 if (*activep && options->ip_qos_interactive == -1) {
2576 options->ip_qos_interactive = value;
2577 options->ip_qos_bulk = value2;
2578 }
2579 break;
2580
2581 case sVersionAddendum:
2582 if (str == NULL || *str == '\0')
2583 fatal("%s line %d: %s missing argument.",
2584 filename, linenum, keyword);
2585 len = strspn(str, WHITESPACE);
2586 if (strchr(str + len, '\r') != NULL) {
2587 fatal("%.200s line %d: Invalid %s argument",
2588 filename, linenum, keyword);
2589 }
2590 if ((arg = strchr(line, '#')) != NULL) {
2591 *arg = '\0';
2592 rtrim(line);
2593 }
2594 if (*activep && options->version_addendum == NULL) {
2595 if (strcasecmp(str + len, "none") == 0)
2596 options->version_addendum = xstrdup("");
2597 else
2598 options->version_addendum = xstrdup(str + len);
2599 }
2600 argv_consume(&ac);
2601 break;
2602
2603 case sAuthorizedKeysCommand:
2604 charptr = &options->authorized_keys_command;
2605 parse_command:
2606 len = strspn(str, WHITESPACE);
2607 if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
2608 fatal("%.200s line %d: %s must be an absolute path",
2609 filename, linenum, keyword);
2610 }
2611 if (*activep && *charptr == NULL)
2612 *charptr = xstrdup(str + len);
2613 argv_consume(&ac);
2614 break;
2615
2616 case sAuthorizedKeysCommandUser:
2617 charptr = &options->authorized_keys_command_user;
2618 parse_localuser:
2619 arg = argv_next(&ac, &av);
2620 if (!arg || *arg == '\0') {
2621 fatal("%s line %d: missing %s argument.",
2622 filename, linenum, keyword);
2623 }
2624 if (*activep && *charptr == NULL)
2625 *charptr = xstrdup(arg);
2626 break;
2627
2628 case sAuthorizedPrincipalsCommand:
2629 charptr = &options->authorized_principals_command;
2630 goto parse_command;
2631
2632 case sAuthorizedPrincipalsCommandUser:
2633 charptr = &options->authorized_principals_command_user;
2634 goto parse_localuser;
2635
2636 case sAuthenticationMethods:
2637 found = options->num_auth_methods == 0;
2638 value = 0; /* seen "any" pseudo-method */
2639 while ((arg = argv_next(&ac, &av)) != NULL) {
2640 if (strcmp(arg, "any") == 0) {
2641 if (nstrs > 0) {
2642 fatal("%s line %d: \"any\" must "
2643 "appear alone in %s",
2644 filename, linenum, keyword);
2645 }
2646 value = 1;
2647 } else if (value) {
2648 fatal("%s line %d: \"any\" must appear "
2649 "alone in %s", filename, linenum, keyword);
2650 } else if (auth2_methods_valid(arg, 0) != 0) {
2651 fatal("%s line %d: invalid %s method list.",
2652 filename, linenum, keyword);
2653 }
2654 opt_array_append(filename, linenum, keyword,
2655 &strs, &nstrs, arg);
2656 }
2657 if (nstrs == 0) {
2658 fatal("%s line %d: no %s specified",
2659 filename, linenum, keyword);
2660 }
2661 if (found && *activep) {
2662 options->auth_methods = strs;
2663 options->num_auth_methods = nstrs;
2664 strs = NULL; /* transferred */
2665 nstrs = 0;
2666 }
2667 break;
2668
2669 case sStreamLocalBindMask:
2670 arg = argv_next(&ac, &av);
2671 if (!arg || *arg == '\0')
2672 fatal("%s line %d: %s missing argument.",
2673 filename, linenum, keyword);
2674 /* Parse mode in octal format */
2675 value = strtol(arg, &p, 8);
2676 if (arg == p || value < 0 || value > 0777)
2677 fatal("%s line %d: Invalid %s.",
2678 filename, linenum, keyword);
2679 if (*activep)
2680 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2681 break;
2682
2683 case sStreamLocalBindUnlink:
2684 intptr = &options->fwd_opts.streamlocal_bind_unlink;
2685 goto parse_flag;
2686
2687 case sFingerprintHash:
2688 arg = argv_next(&ac, &av);
2689 if (!arg || *arg == '\0')
2690 fatal("%s line %d: %s missing argument.",
2691 filename, linenum, keyword);
2692 if ((value = ssh_digest_alg_by_name(arg)) == -1)
2693 fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
2694 filename, linenum, keyword, arg);
2695 if (*activep)
2696 options->fingerprint_hash = value;
2697 break;
2698
2699 case sExposeAuthInfo:
2700 intptr = &options->expose_userauth_info;
2701 goto parse_flag;
2702
2703 case sRDomain:
2704 #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
2705 fatal("%s line %d: setting RDomain not supported on this "
2706 "platform.", filename, linenum);
2707 #endif
2708 charptr = &options->routing_domain;
2709 arg = argv_next(&ac, &av);
2710 if (!arg || *arg == '\0')
2711 fatal("%s line %d: %s missing argument.",
2712 filename, linenum, keyword);
2713 if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
2714 !valid_rdomain(arg))
2715 fatal("%s line %d: invalid routing domain",
2716 filename, linenum);
2717 if (*activep && *charptr == NULL)
2718 *charptr = xstrdup(arg);
2719 break;
2720
2721 case sRequiredRSASize:
2722 intptr = &options->required_rsa_size;
2723 goto parse_int;
2724
2725 case sChannelTimeout:
2726 found = options->num_channel_timeouts == 0;
2727 while ((arg = argv_next(&ac, &av)) != NULL) {
2728 /* Allow "none" only in first position */
2729 if (strcasecmp(arg, "none") == 0) {
2730 if (nstrs > 0 || ac > 0) {
2731 error("%s line %d: keyword %s \"none\" "
2732 "argument must appear alone.",
2733 filename, linenum, keyword);
2734 goto out;
2735 }
2736 } else if (parse_pattern_interval(arg,
2737 NULL, NULL) != 0) {
2738 fatal("%s line %d: invalid channel timeout %s",
2739 filename, linenum, arg);
2740 }
2741 opt_array_append(filename, linenum, keyword,
2742 &strs, &nstrs, arg);
2743 }
2744 if (nstrs == 0) {
2745 fatal("%s line %d: no %s specified",
2746 filename, linenum, keyword);
2747 }
2748 if (found && *activep) {
2749 options->channel_timeouts = strs;
2750 options->num_channel_timeouts = nstrs;
2751 strs = NULL; /* transferred */
2752 nstrs = 0;
2753 }
2754 break;
2755
2756 case sUnusedConnectionTimeout:
2757 intptr = &options->unused_connection_timeout;
2758 /* peek at first arg for "none" so we can reuse parse_time */
2759 if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2760 (void)argv_next(&ac, &av); /* consume arg */
2761 if (*activep)
2762 *intptr = 0;
2763 break;
2764 }
2765 goto parse_time;
2766
2767 case sSshdSessionPath:
2768 charptr = &options->sshd_session_path;
2769 goto parse_filename;
2770
2771 case sSshdAuthPath:
2772 charptr = &options->sshd_auth_path;
2773 goto parse_filename;
2774
2775 case sRefuseConnection:
2776 intptr = &options->refuse_connection;
2777 multistate_ptr = multistate_flag;
2778 goto parse_multistate;
2779
2780 case sUseBlocklist:
2781 intptr = &options->use_blocklist;
2782 goto parse_flag;
2783
2784 case sDeprecated:
2785 case sIgnore:
2786 case sUnsupported:
2787 do_log2(opcode == sIgnore ?
2788 SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2789 "%s line %d: %s option %s", filename, linenum,
2790 opcode == sUnsupported ? "Unsupported" : "Deprecated",
2791 keyword);
2792 argv_consume(&ac);
2793 break;
2794
2795 default:
2796 fatal("%s line %d: Missing handler for opcode %s (%d)",
2797 filename, linenum, keyword, opcode);
2798 }
2799 /* Check that there is no garbage at end of line. */
2800 if (ac > 0) {
2801 error("%.200s line %d: keyword %s extra arguments "
2802 "at end of line", filename, linenum, keyword);
2803 goto out;
2804 }
2805
2806 /* success */
2807 ret = 0;
2808 out:
2809 opt_array_free2(strs, NULL, nstrs);
2810 argv_free(oav, oac);
2811 return ret;
2812 }
2813
2814 int
process_server_config_line(ServerOptions * options,char * line,const char * filename,int linenum,int * activep,struct connection_info * connectinfo,struct include_list * includes)2815 process_server_config_line(ServerOptions *options, char *line,
2816 const char *filename, int linenum, int *activep,
2817 struct connection_info *connectinfo, struct include_list *includes)
2818 {
2819 int inc_flags = 0;
2820
2821 return process_server_config_line_depth(options, line, filename,
2822 linenum, activep, connectinfo, &inc_flags, 0, includes);
2823 }
2824
2825
2826 /* Reads the server configuration file. */
2827
2828 void
load_server_config(const char * filename,struct sshbuf * conf)2829 load_server_config(const char *filename, struct sshbuf *conf)
2830 {
2831 struct stat st;
2832 char *line = NULL, *cp;
2833 size_t linesize = 0;
2834 FILE *f;
2835 int r;
2836
2837 debug2_f("filename %s", filename);
2838 if ((f = fopen(filename, "r")) == NULL) {
2839 perror(filename);
2840 exit(1);
2841 }
2842 sshbuf_reset(conf);
2843 /* grow buffer, so realloc is avoided for large config files */
2844 if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
2845 (r = sshbuf_allocate(conf, st.st_size)) != 0)
2846 fatal_fr(r, "allocate");
2847 while (getline(&line, &linesize, f) != -1) {
2848 /*
2849 * Strip whitespace
2850 * NB - preserve newlines, they are needed to reproduce
2851 * line numbers later for error messages
2852 */
2853 cp = line + strspn(line, " \t\r");
2854 if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
2855 fatal_fr(r, "sshbuf_put");
2856 }
2857 free(line);
2858 if ((r = sshbuf_put_u8(conf, 0)) != 0)
2859 fatal_fr(r, "sshbuf_put_u8");
2860 fclose(f);
2861 debug2_f("done config len = %zu", sshbuf_len(conf));
2862 }
2863
2864 void
parse_server_match_config(ServerOptions * options,struct include_list * includes,struct connection_info * connectinfo)2865 parse_server_match_config(ServerOptions *options,
2866 struct include_list *includes, struct connection_info *connectinfo)
2867 {
2868 ServerOptions mo;
2869
2870 initialize_server_options(&mo);
2871 parse_server_config(&mo, "reprocess config", cfg, includes,
2872 connectinfo, 0);
2873 copy_set_server_options(options, &mo, 0);
2874 }
2875
2876 int
parse_server_match_testspec(struct connection_info * ci,char * spec)2877 parse_server_match_testspec(struct connection_info *ci, char *spec)
2878 {
2879 char *p;
2880 const char *val;
2881
2882 while ((p = strsep(&spec, ",")) && *p != '\0') {
2883 if ((val = strprefix(p, "addr=", 0)) != NULL) {
2884 ci->address = xstrdup(val);
2885 } else if ((val = strprefix(p, "host=", 0)) != NULL) {
2886 ci->host = xstrdup(val);
2887 } else if ((val = strprefix(p, "user=", 0)) != NULL) {
2888 ci->user = xstrdup(val);
2889 } else if ((val = strprefix(p, "laddr=", 0)) != NULL) {
2890 ci->laddress = xstrdup(val);
2891 } else if ((val = strprefix(p, "rdomain=", 0)) != NULL) {
2892 ci->rdomain = xstrdup(val);
2893 } else if ((val = strprefix(p, "lport=", 0)) != NULL) {
2894 ci->lport = a2port(val);
2895 if (ci->lport == -1) {
2896 fprintf(stderr, "Invalid port '%s' in test mode"
2897 " specification %s\n", p+6, p);
2898 return -1;
2899 }
2900 } else if (strcmp(p, "invalid-user") == 0) {
2901 ci->user_invalid = 1;
2902 } else {
2903 fprintf(stderr, "Invalid test mode specification %s\n",
2904 p);
2905 return -1;
2906 }
2907 }
2908 return 0;
2909 }
2910
2911 void
servconf_merge_subsystems(ServerOptions * dst,ServerOptions * src)2912 servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
2913 {
2914 u_int i, j, found;
2915
2916 for (i = 0; i < src->num_subsystems; i++) {
2917 found = 0;
2918 for (j = 0; j < dst->num_subsystems; j++) {
2919 if (strcmp(src->subsystem_name[i],
2920 dst->subsystem_name[j]) == 0) {
2921 found = 1;
2922 break;
2923 }
2924 }
2925 if (found) {
2926 debug_f("override \"%s\"", dst->subsystem_name[j]);
2927 free(dst->subsystem_command[j]);
2928 free(dst->subsystem_args[j]);
2929 dst->subsystem_command[j] =
2930 xstrdup(src->subsystem_command[i]);
2931 dst->subsystem_args[j] =
2932 xstrdup(src->subsystem_args[i]);
2933 continue;
2934 }
2935 debug_f("add \"%s\"", src->subsystem_name[i]);
2936 dst->subsystem_name = xrecallocarray(
2937 dst->subsystem_name, dst->num_subsystems,
2938 dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
2939 dst->subsystem_command = xrecallocarray(
2940 dst->subsystem_command, dst->num_subsystems,
2941 dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
2942 dst->subsystem_args = xrecallocarray(
2943 dst->subsystem_args, dst->num_subsystems,
2944 dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
2945 j = dst->num_subsystems++;
2946 dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
2947 dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
2948 dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
2949 }
2950 }
2951
2952 /*
2953 * Copy any supported values that are set.
2954 *
2955 * If the preauth flag is set, we do not bother copying the string or
2956 * array values that are not used pre-authentication, because any that we
2957 * do use must be explicitly sent in mm_getpwnamallow().
2958 */
2959 void
copy_set_server_options(ServerOptions * dst,ServerOptions * src,int preauth)2960 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2961 {
2962 #define M_CP_INTOPT(n) do {\
2963 if (src->n != -1) \
2964 dst->n = src->n; \
2965 } while (0)
2966
2967 M_CP_INTOPT(password_authentication);
2968 M_CP_INTOPT(gss_authentication);
2969 M_CP_INTOPT(pubkey_authentication);
2970 M_CP_INTOPT(pubkey_auth_options);
2971 M_CP_INTOPT(kerberos_authentication);
2972 M_CP_INTOPT(hostbased_authentication);
2973 M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2974 M_CP_INTOPT(kbd_interactive_authentication);
2975 M_CP_INTOPT(permit_root_login);
2976 M_CP_INTOPT(permit_empty_passwd);
2977 M_CP_INTOPT(ignore_rhosts);
2978
2979 M_CP_INTOPT(allow_tcp_forwarding);
2980 M_CP_INTOPT(allow_streamlocal_forwarding);
2981 M_CP_INTOPT(allow_agent_forwarding);
2982 M_CP_INTOPT(disable_forwarding);
2983 M_CP_INTOPT(expose_userauth_info);
2984 M_CP_INTOPT(permit_tun);
2985 M_CP_INTOPT(fwd_opts.gateway_ports);
2986 M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2987 M_CP_INTOPT(x11_display_offset);
2988 M_CP_INTOPT(x11_forwarding);
2989 M_CP_INTOPT(x11_use_localhost);
2990 M_CP_INTOPT(permit_tty);
2991 M_CP_INTOPT(permit_user_rc);
2992 M_CP_INTOPT(max_sessions);
2993 M_CP_INTOPT(max_authtries);
2994 M_CP_INTOPT(client_alive_count_max);
2995 M_CP_INTOPT(client_alive_interval);
2996 M_CP_INTOPT(ip_qos_interactive);
2997 M_CP_INTOPT(ip_qos_bulk);
2998 M_CP_INTOPT(rekey_limit);
2999 M_CP_INTOPT(rekey_interval);
3000 M_CP_INTOPT(log_level);
3001 M_CP_INTOPT(required_rsa_size);
3002 M_CP_INTOPT(unused_connection_timeout);
3003 M_CP_INTOPT(refuse_connection);
3004
3005 /*
3006 * The bind_mask is a mode_t that may be unsigned, so we can't use
3007 * M_CP_INTOPT - it does a signed comparison that causes compiler
3008 * warnings.
3009 */
3010 if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
3011 dst->fwd_opts.streamlocal_bind_mask =
3012 src->fwd_opts.streamlocal_bind_mask;
3013 }
3014
3015 /* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
3016 #define M_CP_STROPT(n) do {\
3017 if (src->n != NULL && dst->n != src->n) { \
3018 free(dst->n); \
3019 dst->n = xstrdup(src->n); \
3020 } \
3021 } while(0)
3022 #define M_CP_STRARRAYOPT(s, num_s, clobber) do {\
3023 u_int i; \
3024 if (src->num_s != 0) { \
3025 for (i = 0; i < dst->num_s; i++) \
3026 free(dst->s[i]); \
3027 free(dst->s); \
3028 dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
3029 for (i = 0; i < src->num_s; i++) \
3030 dst->s[i] = xstrdup(src->s[i]); \
3031 if (clobber) \
3032 dst->num_s = src->num_s; \
3033 } \
3034 } while(0)
3035
3036 /* See comment in servconf.h */
3037 COPY_MATCH_STRING_OPTS();
3038
3039 /* Arguments that accept '+...' need to be expanded */
3040 assemble_algorithms(dst);
3041
3042 /*
3043 * The only things that should be below this point are string options
3044 * which are only used after authentication.
3045 */
3046 if (preauth)
3047 return;
3048
3049 /* These options may be "none" to clear a global setting */
3050 M_CP_STROPT(adm_forced_command);
3051 if (option_clear_or_none(dst->adm_forced_command)) {
3052 free(dst->adm_forced_command);
3053 dst->adm_forced_command = NULL;
3054 }
3055 M_CP_STROPT(chroot_directory);
3056 if (option_clear_or_none(dst->chroot_directory)) {
3057 free(dst->chroot_directory);
3058 dst->chroot_directory = NULL;
3059 }
3060
3061 /* Subsystems require merging. */
3062 servconf_merge_subsystems(dst, src);
3063 }
3064
3065 #undef M_CP_INTOPT
3066 #undef M_CP_STROPT
3067 #undef M_CP_STRARRAYOPT
3068
3069 #define SERVCONF_MAX_DEPTH 16
3070 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)3071 parse_server_config_depth(ServerOptions *options, const char *filename,
3072 struct sshbuf *conf, struct include_list *includes,
3073 struct connection_info *connectinfo, int flags, int *activep, int depth)
3074 {
3075 int linenum, bad_options = 0;
3076 char *cp, *obuf, *cbuf;
3077
3078 if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
3079 fatal("Too many recursive configuration includes");
3080
3081 debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
3082 (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
3083
3084 if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
3085 fatal_f("sshbuf_dup_string failed");
3086 linenum = 1;
3087 while ((cp = strsep(&cbuf, "\n")) != NULL) {
3088 if (process_server_config_line_depth(options, cp,
3089 filename, linenum++, activep, connectinfo, &flags,
3090 depth, includes) != 0)
3091 bad_options++;
3092 }
3093 free(obuf);
3094 if (bad_options > 0)
3095 fatal("%s: terminating, %d bad configuration options",
3096 filename, bad_options);
3097 }
3098
3099 void
parse_server_config(ServerOptions * options,const char * filename,struct sshbuf * conf,struct include_list * includes,struct connection_info * connectinfo,int reexec)3100 parse_server_config(ServerOptions *options, const char *filename,
3101 struct sshbuf *conf, struct include_list *includes,
3102 struct connection_info *connectinfo, int reexec)
3103 {
3104 int active = connectinfo ? 0 : 1;
3105 parse_server_config_depth(options, filename, conf, includes,
3106 connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
3107 if (!reexec)
3108 process_queued_listen_addrs(options);
3109 }
3110
3111 static const char *
fmt_multistate_int(int val,const struct multistate * m)3112 fmt_multistate_int(int val, const struct multistate *m)
3113 {
3114 u_int i;
3115
3116 for (i = 0; m[i].key != NULL; i++) {
3117 if (m[i].value == val)
3118 return m[i].key;
3119 }
3120 return "UNKNOWN";
3121 }
3122
3123 static const char *
fmt_intarg(ServerOpCodes code,int val)3124 fmt_intarg(ServerOpCodes code, int val)
3125 {
3126 if (val == -1)
3127 return "unset";
3128 switch (code) {
3129 case sAddressFamily:
3130 return fmt_multistate_int(val, multistate_addressfamily);
3131 case sPermitRootLogin:
3132 return fmt_multistate_int(val, multistate_permitrootlogin);
3133 case sGatewayPorts:
3134 return fmt_multistate_int(val, multistate_gatewayports);
3135 case sCompression:
3136 return fmt_multistate_int(val, multistate_compression);
3137 case sAllowTcpForwarding:
3138 return fmt_multistate_int(val, multistate_tcpfwd);
3139 case sAllowStreamLocalForwarding:
3140 return fmt_multistate_int(val, multistate_tcpfwd);
3141 case sIgnoreRhosts:
3142 return fmt_multistate_int(val, multistate_ignore_rhosts);
3143 case sFingerprintHash:
3144 return ssh_digest_alg_name(val);
3145 default:
3146 switch (val) {
3147 case 0:
3148 return "no";
3149 case 1:
3150 return "yes";
3151 default:
3152 return "UNKNOWN";
3153 }
3154 }
3155 }
3156
3157 static void
dump_cfg_int(ServerOpCodes code,int val)3158 dump_cfg_int(ServerOpCodes code, int val)
3159 {
3160 if (code == sUnusedConnectionTimeout && val == 0) {
3161 printf("%s none\n", lookup_opcode_name(code));
3162 return;
3163 }
3164 printf("%s %d\n", lookup_opcode_name(code), val);
3165 }
3166
3167 static void
dump_cfg_oct(ServerOpCodes code,int val)3168 dump_cfg_oct(ServerOpCodes code, int val)
3169 {
3170 printf("%s 0%o\n", lookup_opcode_name(code), val);
3171 }
3172
3173 static void
dump_cfg_fmtint(ServerOpCodes code,int val)3174 dump_cfg_fmtint(ServerOpCodes code, int val)
3175 {
3176 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3177 }
3178
3179 static void
dump_cfg_string(ServerOpCodes code,const char * val)3180 dump_cfg_string(ServerOpCodes code, const char *val)
3181 {
3182 printf("%s %s\n", lookup_opcode_name(code),
3183 val == NULL ? "none" : val);
3184 }
3185
3186 static void
dump_cfg_strarray(ServerOpCodes code,u_int count,char ** vals)3187 dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
3188 {
3189 u_int i;
3190
3191 for (i = 0; i < count; i++)
3192 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3193 }
3194
3195 static void
dump_cfg_strarray_oneline(ServerOpCodes code,u_int count,char ** vals)3196 dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
3197 {
3198 u_int i;
3199
3200 switch (code) {
3201 case sAuthenticationMethods:
3202 case sChannelTimeout:
3203 break;
3204 default:
3205 if (count <= 0)
3206 return;
3207 break;
3208 }
3209
3210 printf("%s", lookup_opcode_name(code));
3211 for (i = 0; i < count; i++)
3212 printf(" %s", vals[i]);
3213 if (code == sAuthenticationMethods && count == 0)
3214 printf(" any");
3215 else if (code == sChannelTimeout && count == 0)
3216 printf(" none");
3217 printf("\n");
3218 }
3219
3220 static char *
format_listen_addrs(struct listenaddr * la)3221 format_listen_addrs(struct listenaddr *la)
3222 {
3223 int r;
3224 struct addrinfo *ai;
3225 char addr[NI_MAXHOST], port[NI_MAXSERV];
3226 char *laddr1 = xstrdup(""), *laddr2 = NULL;
3227
3228 /*
3229 * ListenAddress must be after Port. add_one_listen_addr pushes
3230 * addresses onto a stack, so to maintain ordering we need to
3231 * print these in reverse order.
3232 */
3233 for (ai = la->addrs; ai; ai = ai->ai_next) {
3234 if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
3235 sizeof(addr), port, sizeof(port),
3236 NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
3237 error("getnameinfo: %.100s", ssh_gai_strerror(r));
3238 continue;
3239 }
3240 laddr2 = laddr1;
3241 if (ai->ai_family == AF_INET6) {
3242 xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
3243 addr, port,
3244 la->rdomain == NULL ? "" : " rdomain ",
3245 la->rdomain == NULL ? "" : la->rdomain,
3246 laddr2);
3247 } else {
3248 xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
3249 addr, port,
3250 la->rdomain == NULL ? "" : " rdomain ",
3251 la->rdomain == NULL ? "" : la->rdomain,
3252 laddr2);
3253 }
3254 free(laddr2);
3255 }
3256 return laddr1;
3257 }
3258
3259 void
dump_config(ServerOptions * o)3260 dump_config(ServerOptions *o)
3261 {
3262 char *s;
3263 u_int i;
3264
3265 /* these are usually at the top of the config */
3266 for (i = 0; i < o->num_ports; i++)
3267 printf("port %d\n", o->ports[i]);
3268 dump_cfg_fmtint(sAddressFamily, o->address_family);
3269
3270 for (i = 0; i < o->num_listen_addrs; i++) {
3271 s = format_listen_addrs(&o->listen_addrs[i]);
3272 printf("%s", s);
3273 free(s);
3274 }
3275
3276 /* integer arguments */
3277 #ifdef USE_PAM
3278 dump_cfg_fmtint(sUsePAM, o->use_pam);
3279 dump_cfg_string(sPAMServiceName, o->pam_service_name);
3280 #endif
3281 dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3282 dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3283 dump_cfg_int(sMaxAuthTries, o->max_authtries);
3284 dump_cfg_int(sMaxSessions, o->max_sessions);
3285 dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3286 dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
3287 dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3288 dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3289 dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3290
3291 /* formatted integer arguments */
3292 dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3293 dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3294 dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3295 dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3296 dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3297 o->hostbased_uses_name_from_packet_only);
3298 dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3299 #ifdef KRB5
3300 dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3301 dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3302 dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3303 # ifdef USE_AFS
3304 dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3305 # endif
3306 #endif
3307 #ifdef GSSAPI
3308 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3309 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3310 dump_cfg_fmtint(sGssDelegateCreds, o->gss_deleg_creds);
3311 dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
3312 #endif
3313 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3314 dump_cfg_fmtint(sKbdInteractiveAuthentication,
3315 o->kbd_interactive_authentication);
3316 dump_cfg_fmtint(sPrintMotd, o->print_motd);
3317 #ifndef DISABLE_LASTLOG
3318 dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3319 #endif
3320 dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3321 dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3322 dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3323 dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3324 dump_cfg_fmtint(sStrictModes, o->strict_modes);
3325 dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3326 dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3327 dump_cfg_fmtint(sCompression, o->compression);
3328 dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3329 dump_cfg_fmtint(sUseDNS, o->use_dns);
3330 dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3331 dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3332 dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3333 dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3334 dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3335 dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
3336 dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
3337 dump_cfg_fmtint(sRefuseConnection, o->refuse_connection);
3338 dump_cfg_fmtint(sUseBlocklist, o->use_blocklist);
3339
3340 /* string arguments */
3341 dump_cfg_string(sPidFile, o->pid_file);
3342 dump_cfg_string(sModuliFile, o->moduli_file);
3343 dump_cfg_string(sXAuthLocation, o->xauth_location);
3344 dump_cfg_string(sCiphers, o->ciphers);
3345 dump_cfg_string(sMacs, o->macs);
3346 dump_cfg_string(sBanner, o->banner);
3347 dump_cfg_string(sForceCommand, o->adm_forced_command);
3348 dump_cfg_string(sChrootDirectory, o->chroot_directory);
3349 dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3350 dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3351 dump_cfg_string(sAuthorizedPrincipalsFile,
3352 o->authorized_principals_file);
3353 dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3354 ? "none" : o->version_addendum);
3355 dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
3356 dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3357 dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3358 dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3359 dump_cfg_string(sHostKeyAgent, o->host_key_agent);
3360 dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
3361 dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
3362 dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3363 dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
3364 dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3365 #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
3366 dump_cfg_string(sRDomain, o->routing_domain);
3367 #endif
3368 dump_cfg_string(sSshdSessionPath, o->sshd_session_path);
3369 dump_cfg_string(sSshdAuthPath, o->sshd_auth_path);
3370 dump_cfg_string(sPerSourcePenaltyExemptList, o->per_source_penalty_exempt);
3371
3372 /* string arguments requiring a lookup */
3373 dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3374 dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3375
3376 /* string array arguments */
3377 dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3378 o->authorized_keys_files);
3379 dump_cfg_strarray_oneline(sRevokedKeys, o->num_revoked_keys_files,
3380 o->revoked_keys_files);
3381 dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3382 o->host_key_files);
3383 dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3384 o->host_cert_files);
3385 dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3386 dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3387 dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3388 dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3389 dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3390 dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
3391 dump_cfg_strarray_oneline(sAuthenticationMethods,
3392 o->num_auth_methods, o->auth_methods);
3393 dump_cfg_strarray_oneline(sLogVerbose,
3394 o->num_log_verbose, o->log_verbose);
3395 dump_cfg_strarray_oneline(sChannelTimeout,
3396 o->num_channel_timeouts, o->channel_timeouts);
3397
3398 /* other arguments */
3399 for (i = 0; i < o->num_subsystems; i++)
3400 printf("subsystem %s %s\n", o->subsystem_name[i],
3401 o->subsystem_args[i]);
3402
3403 printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3404 o->max_startups_rate, o->max_startups);
3405 printf("persourcemaxstartups ");
3406 if (o->per_source_max_startups == INT_MAX)
3407 printf("none\n");
3408 else
3409 printf("%d\n", o->per_source_max_startups);
3410 printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
3411 o->per_source_masklen_ipv6);
3412
3413 s = NULL;
3414 for (i = 0; tunmode_desc[i].val != -1; i++) {
3415 if (tunmode_desc[i].val == o->permit_tun) {
3416 s = tunmode_desc[i].text;
3417 break;
3418 }
3419 }
3420 dump_cfg_string(sPermitTunnel, s);
3421
3422 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3423 printf("%s\n", iptos2str(o->ip_qos_bulk));
3424
3425 printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3426 o->rekey_interval);
3427
3428 printf("permitopen");
3429 if (o->num_permitted_opens == 0)
3430 printf(" any");
3431 else {
3432 for (i = 0; i < o->num_permitted_opens; i++)
3433 printf(" %s", o->permitted_opens[i]);
3434 }
3435 printf("\n");
3436 printf("permitlisten");
3437 if (o->num_permitted_listens == 0)
3438 printf(" any");
3439 else {
3440 for (i = 0; i < o->num_permitted_listens; i++)
3441 printf(" %s", o->permitted_listens[i]);
3442 }
3443 printf("\n");
3444
3445 if (o->permit_user_env_allowlist == NULL) {
3446 dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3447 } else {
3448 printf("permituserenvironment %s\n",
3449 o->permit_user_env_allowlist);
3450 }
3451
3452 printf("pubkeyauthoptions");
3453 if (o->pubkey_auth_options == 0)
3454 printf(" none");
3455 if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
3456 printf(" touch-required");
3457 if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
3458 printf(" verify-required");
3459 printf("\n");
3460
3461 if (o->per_source_penalty.enabled) {
3462 printf("persourcepenalties crash:%f authfail:%f noauth:%f "
3463 "invaliduser:%f "
3464 "grace-exceeded:%f refuseconnection:%f max:%f min:%f "
3465 "max-sources4:%d max-sources6:%d "
3466 "overflow:%s overflow6:%s\n",
3467 o->per_source_penalty.penalty_crash,
3468 o->per_source_penalty.penalty_authfail,
3469 o->per_source_penalty.penalty_noauth,
3470 o->per_source_penalty.penalty_invaliduser,
3471 o->per_source_penalty.penalty_grace,
3472 o->per_source_penalty.penalty_refuseconnection,
3473 o->per_source_penalty.penalty_max,
3474 o->per_source_penalty.penalty_min,
3475 o->per_source_penalty.max_sources4,
3476 o->per_source_penalty.max_sources6,
3477 o->per_source_penalty.overflow_mode ==
3478 PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
3479 "deny-all" : "permissive",
3480 o->per_source_penalty.overflow_mode6 ==
3481 PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
3482 "deny-all" : "permissive");
3483 } else
3484 printf("persourcepenalties no\n");
3485 }
3486