1 /* $OpenBSD: servconf.c,v 1.165 2006/08/14 12:40:25 dtucker Exp $ */
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
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".
15 #include <sys/types.h>
16 #include <sys/socket.h>
33 #include "pathnames.h"
41 #include "groupaccess.h"
43 static void add_listen_addr(ServerOptions *, char *, u_short);
44 static void add_one_listen_addr(ServerOptions *, char *, u_short);
46 /* Use of privilege separation or not */
47 extern int use_privsep;
50 /* Initializes the server options to their default values. */
53 initialize_server_options(ServerOptions *options)
55 memset(options, 0, sizeof(*options));
57 /* Portable-specific options */
58 options->use_pam = -1;
60 /* Standard Options */
61 options->num_ports = 0;
62 options->ports_from_cmdline = 0;
63 options->listen_addrs = NULL;
64 options->address_family = -1;
65 options->num_host_key_files = 0;
66 options->pid_file = NULL;
67 options->server_key_bits = -1;
68 options->login_grace_time = -1;
69 options->key_regeneration_time = -1;
70 options->permit_root_login = PERMIT_NOT_SET;
71 options->ignore_rhosts = -1;
72 options->ignore_user_known_hosts = -1;
73 options->print_motd = -1;
74 options->print_lastlog = -1;
75 options->x11_forwarding = -1;
76 options->x11_display_offset = -1;
77 options->x11_use_localhost = -1;
78 options->xauth_location = NULL;
79 options->strict_modes = -1;
80 options->tcp_keep_alive = -1;
81 options->log_facility = SYSLOG_FACILITY_NOT_SET;
82 options->log_level = SYSLOG_LEVEL_NOT_SET;
83 options->rhosts_rsa_authentication = -1;
84 options->hostbased_authentication = -1;
85 options->hostbased_uses_name_from_packet_only = -1;
86 options->rsa_authentication = -1;
87 options->pubkey_authentication = -1;
88 options->kerberos_authentication = -1;
89 options->kerberos_or_local_passwd = -1;
90 options->kerberos_ticket_cleanup = -1;
92 options->session_hooks_allow = -1;
93 options->session_hooks_startup_cmd = NULL;
94 options->session_hooks_shutdown_cmd = NULL;
96 options->kerberos_get_afs_token = -1;
97 options->gss_authentication=-1;
98 options->gss_keyex = -1;
99 options->gss_cleanup_creds = -1;
100 options->gss_strict_acceptor = -1;
101 options->gsi_allow_limited_proxy = -1;
102 options->password_authentication = -1;
103 options->kbd_interactive_authentication = -1;
104 options->challenge_response_authentication = -1;
105 options->permit_empty_passwd = -1;
106 options->permit_user_env = -1;
107 options->use_login = -1;
108 options->compression = -1;
109 options->allow_tcp_forwarding = -1;
110 options->num_allow_users = 0;
111 options->num_deny_users = 0;
112 options->num_allow_groups = 0;
113 options->num_deny_groups = 0;
114 options->ciphers = NULL;
115 options->macs = NULL;
116 options->protocol = SSH_PROTO_UNKNOWN;
117 options->gateway_ports = -1;
118 options->num_subsystems = 0;
119 options->max_startups_begin = -1;
120 options->max_startups_rate = -1;
121 options->max_startups = -1;
122 options->max_authtries = -1;
123 options->banner = NULL;
124 options->use_dns = -1;
125 options->client_alive_interval = -1;
126 options->client_alive_count_max = -1;
127 options->authorized_keys_file = NULL;
128 options->authorized_keys_file2 = NULL;
129 options->num_accept_env = 0;
130 options->permit_tun = -1;
131 options->num_permitted_opens = -1;
132 options->adm_forced_command = NULL;
133 options->none_enabled = -1;
134 options->tcp_rcv_buf_poll = -1;
135 options->hpn_disabled = -1;
136 options->hpn_buffer_size = -1;
140 fill_default_server_options(ServerOptions *options)
143 /* Portable-specific options */
144 if (options->use_pam == -1)
145 options->use_pam = 0;
147 /* Standard Options */
148 if (options->protocol == SSH_PROTO_UNKNOWN)
149 options->protocol = SSH_PROTO_1|SSH_PROTO_2;
150 if (options->num_host_key_files == 0) {
151 /* fill default hostkeys for protocols */
152 if (options->protocol & SSH_PROTO_1)
153 options->host_key_files[options->num_host_key_files++] =
155 if (options->protocol & SSH_PROTO_2) {
156 options->host_key_files[options->num_host_key_files++] =
157 _PATH_HOST_RSA_KEY_FILE;
158 options->host_key_files[options->num_host_key_files++] =
159 _PATH_HOST_DSA_KEY_FILE;
162 if (options->num_ports == 0)
163 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
164 if (options->listen_addrs == NULL)
165 add_listen_addr(options, NULL, 0);
166 if (options->pid_file == NULL)
167 options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
168 if (options->server_key_bits == -1)
169 options->server_key_bits = 768;
170 if (options->login_grace_time == -1)
171 options->login_grace_time = 120;
172 if (options->key_regeneration_time == -1)
173 options->key_regeneration_time = 3600;
174 if (options->permit_root_login == PERMIT_NOT_SET)
175 options->permit_root_login = PERMIT_YES;
176 if (options->ignore_rhosts == -1)
177 options->ignore_rhosts = 1;
178 if (options->ignore_user_known_hosts == -1)
179 options->ignore_user_known_hosts = 0;
180 if (options->print_motd == -1)
181 options->print_motd = 1;
182 if (options->print_lastlog == -1)
183 options->print_lastlog = 1;
184 if (options->x11_forwarding == -1)
185 options->x11_forwarding = 0;
186 if (options->x11_display_offset == -1)
187 options->x11_display_offset = 10;
188 if (options->x11_use_localhost == -1)
189 options->x11_use_localhost = 1;
190 if (options->xauth_location == NULL)
191 options->xauth_location = _PATH_XAUTH;
192 if (options->strict_modes == -1)
193 options->strict_modes = 1;
194 if (options->tcp_keep_alive == -1)
195 options->tcp_keep_alive = 1;
196 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
197 options->log_facility = SYSLOG_FACILITY_AUTH;
198 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
199 options->log_level = SYSLOG_LEVEL_INFO;
200 if (options->rhosts_rsa_authentication == -1)
201 options->rhosts_rsa_authentication = 0;
202 if (options->hostbased_authentication == -1)
203 options->hostbased_authentication = 0;
204 if (options->hostbased_uses_name_from_packet_only == -1)
205 options->hostbased_uses_name_from_packet_only = 0;
206 if (options->rsa_authentication == -1)
207 options->rsa_authentication = 1;
208 if (options->pubkey_authentication == -1)
209 options->pubkey_authentication = 1;
210 if (options->kerberos_authentication == -1)
211 options->kerberos_authentication = 0;
212 if (options->kerberos_or_local_passwd == -1)
213 options->kerberos_or_local_passwd = 1;
214 if (options->kerberos_ticket_cleanup == -1)
215 options->kerberos_ticket_cleanup = 1;
216 if (options->kerberos_get_afs_token == -1)
217 options->kerberos_get_afs_token = 0;
218 if (options->gss_authentication == -1)
219 options->gss_authentication = 1;
220 if (options->gss_keyex == -1)
221 options->gss_keyex = 1;
222 if (options->gss_cleanup_creds == -1)
223 options->gss_cleanup_creds = 1;
224 if (options->gss_strict_acceptor == -1)
225 options->gss_strict_acceptor = 0;
226 if (options->gsi_allow_limited_proxy == -1)
227 options->gsi_allow_limited_proxy = 0;
228 if (options->password_authentication == -1)
229 options->password_authentication = 1;
230 if (options->kbd_interactive_authentication == -1)
231 options->kbd_interactive_authentication = 0;
232 if (options->challenge_response_authentication == -1)
233 options->challenge_response_authentication = 1;
234 if (options->permit_empty_passwd == -1)
235 options->permit_empty_passwd = 0;
236 if (options->permit_user_env == -1)
237 options->permit_user_env = 0;
238 if (options->use_login == -1)
239 options->use_login = 0;
240 if (options->compression == -1)
241 options->compression = COMP_DELAYED;
242 if (options->allow_tcp_forwarding == -1)
243 options->allow_tcp_forwarding = 1;
244 if (options->gateway_ports == -1)
245 options->gateway_ports = 0;
246 if (options->max_startups == -1)
247 options->max_startups = 10;
248 if (options->max_startups_rate == -1)
249 options->max_startups_rate = 100; /* 100% */
250 if (options->max_startups_begin == -1)
251 options->max_startups_begin = options->max_startups;
252 if (options->max_authtries == -1)
253 options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
254 if (options->use_dns == -1)
255 options->use_dns = 1;
256 if (options->client_alive_interval == -1)
257 options->client_alive_interval = 0;
258 if (options->client_alive_count_max == -1)
259 options->client_alive_count_max = 3;
260 if (options->authorized_keys_file2 == NULL) {
261 /* authorized_keys_file2 falls back to authorized_keys_file */
262 if (options->authorized_keys_file != NULL)
263 options->authorized_keys_file2 = options->authorized_keys_file;
265 options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
267 if (options->authorized_keys_file == NULL)
268 options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
269 if (options->permit_tun == -1)
270 options->permit_tun = SSH_TUNMODE_NO;
272 if (options->hpn_disabled == -1)
273 options->hpn_disabled = 0;
275 if (options->hpn_buffer_size == -1)
276 options->hpn_buffer_size = 2*1024*1024;
278 if (options->hpn_buffer_size == 0)
279 options->hpn_buffer_size = 1;
280 /* limit the maximum buffer to 7MB */
281 if (options->hpn_buffer_size > 7168)
282 options->hpn_buffer_size = 7168;
283 options->hpn_buffer_size *=1024;
286 /* Turn privilege separation on by default */
287 if (use_privsep == -1)
293 if (use_privsep && options->compression == 1) {
294 error("This platform does not support both privilege "
295 "separation and compression");
296 error("Compression disabled");
297 options->compression = 0;
303 /* Keyword tokens. */
305 sBadOption, /* == unknown option */
306 /* Portable-specific options */
308 /* Standard Options */
309 sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
310 sPermitRootLogin, sLogFacility, sLogLevel,
311 sRhostsRSAAuthentication, sRSAAuthentication,
312 sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
313 sKerberosGetAFSToken,
314 sKerberosTgtPassing, sChallengeResponseAuthentication,
316 sAllowSessionHooks, sSessionHookStartupCmd, sSessionHookShutdownCmd,
318 sPasswordAuthentication, sKbdInteractiveAuthentication,
319 sListenAddress, sAddressFamily,
320 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
321 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
322 sStrictModes, sEmptyPasswd, sTCPKeepAlive,
323 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
324 sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
325 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
326 sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
327 sMaxStartups, sMaxAuthTries,
328 sBanner, sUseDNS, sHostbasedAuthentication,
329 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
330 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
331 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
334 sGsiAllowLimitedProxy,
335 sAcceptEnv, sPermitTunnel,
336 sMatch, sPermitOpen, sForceCommand,
337 sUsePrivilegeSeparation,
338 sNoneEnabled, sTcpRcvBufPoll,
339 sHPNDisabled, sHPNBufferSize,
340 sDeprecated, sUnsupported
343 #define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
344 #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
345 #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
347 /* Textual representation of the tokens. */
350 ServerOpCodes opcode;
353 /* Portable-specific options */
355 { "usepam", sUsePAM, SSHCFG_GLOBAL },
357 { "usepam", sUnsupported, SSHCFG_GLOBAL },
359 { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
360 /* Standard Options */
361 { "port", sPort, SSHCFG_GLOBAL },
362 { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
363 { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
364 { "pidfile", sPidFile, SSHCFG_GLOBAL },
365 { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
366 { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
367 { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
368 { "permitrootlogin", sPermitRootLogin, SSHCFG_GLOBAL },
369 { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
370 { "loglevel", sLogLevel, SSHCFG_GLOBAL },
371 { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
372 { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_GLOBAL },
373 { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_GLOBAL },
374 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
375 { "rsaauthentication", sRSAAuthentication, SSHCFG_GLOBAL },
376 { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL },
377 { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
379 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_GLOBAL },
380 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
381 { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
383 { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
385 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
388 { "kerberosauthentication", sUnsupported, SSHCFG_GLOBAL },
389 { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
390 { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
391 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
393 { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
394 { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
396 { "gssapiauthentication", sGssAuthentication, SSHCFG_GLOBAL },
397 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
398 { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL },
399 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
400 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
402 { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL },
405 { "gssapiauthentication", sUnsupported, SSHCFG_GLOBAL },
406 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
407 { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL },
408 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
409 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
411 { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
415 { "allowsessionhooks", sAllowSessionHooks, SSHCFG_GLOBAL },
416 { "sessionhookstartupcmd", sSessionHookStartupCmd, SSHCFG_GLOBAL },
417 { "sessionhookshutdowncmd", sSessionHookShutdownCmd, SSHCFG_GLOBAL },
419 { "passwordauthentication", sPasswordAuthentication, SSHCFG_GLOBAL },
420 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_GLOBAL },
421 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
422 { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
423 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
424 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
425 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
426 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
427 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
428 { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
429 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
430 { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
431 { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
432 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
433 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
434 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
435 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
436 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
437 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
438 { "compression", sCompression, SSHCFG_GLOBAL },
439 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
440 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
441 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
442 { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
443 { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
444 { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
445 { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
446 { "ciphers", sCiphers, SSHCFG_GLOBAL },
447 { "macs", sMacs, SSHCFG_GLOBAL },
448 { "protocol", sProtocol, SSHCFG_GLOBAL },
449 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
450 { "subsystem", sSubsystem, SSHCFG_GLOBAL },
451 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
452 { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
453 { "banner", sBanner, SSHCFG_GLOBAL },
454 { "usedns", sUseDNS, SSHCFG_GLOBAL },
455 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
456 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
457 { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
458 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
459 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
460 { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
461 { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
462 { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
463 { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
464 { "match", sMatch, SSHCFG_ALL },
465 { "permitopen", sPermitOpen, SSHCFG_ALL },
466 { "forcecommand", sForceCommand, SSHCFG_ALL },
467 { "noneenabled", sNoneEnabled },
468 { "hpndisabled", sHPNDisabled },
469 { "hpnbuffersize", sHPNBufferSize },
470 { "tcprcvbufpoll", sTcpRcvBufPoll },
471 { NULL, sBadOption, 0 }
475 * Returns the number of the token pointed to by cp or sBadOption.
479 parse_token(const char *cp, const char *filename,
480 int linenum, u_int *flags)
484 for (i = 0; keywords[i].name; i++)
485 if (strcasecmp(cp, keywords[i].name) == 0) {
486 *flags = keywords[i].flags;
487 return keywords[i].opcode;
490 error("%s: line %d: Bad configuration option: %s",
491 filename, linenum, cp);
496 add_listen_addr(ServerOptions *options, char *addr, u_short port)
500 if (options->num_ports == 0)
501 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
502 if (options->address_family == -1)
503 options->address_family = AF_UNSPEC;
505 for (i = 0; i < options->num_ports; i++)
506 add_one_listen_addr(options, addr, options->ports[i]);
508 add_one_listen_addr(options, addr, port);
512 add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
514 struct addrinfo hints, *ai, *aitop;
515 char strport[NI_MAXSERV];
518 memset(&hints, 0, sizeof(hints));
519 hints.ai_family = options->address_family;
520 hints.ai_socktype = SOCK_STREAM;
521 hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
522 snprintf(strport, sizeof strport, "%u", port);
523 if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
524 fatal("bad addr or host: %s (%s)",
525 addr ? addr : "<NULL>",
526 gai_strerror(gaierr));
527 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
529 ai->ai_next = options->listen_addrs;
530 options->listen_addrs = aitop;
534 * The strategy for the Match blocks is that the config file is parsed twice.
536 * The first time is at startup. activep is initialized to 1 and the
537 * directives in the global context are processed and acted on. Hitting a
538 * Match directive unsets activep and the directives inside the block are
539 * checked for syntax only.
541 * The second time is after a connection has been established but before
542 * authentication. activep is initialized to 2 and global config directives
543 * are ignored since they have already been processed. If the criteria in a
544 * Match block is met, activep is set and the subsequent directives
545 * processed and actioned until EOF or another Match block unsets it. Any
546 * options set are copied into the main server config.
548 * Potential additions/improvements:
549 * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
551 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
552 * Match Address 192.168.0.*
557 * AllowTcpForwarding yes
558 * GatewayPorts clientspecified
561 * - Add a PermittedChannelRequests directive
563 * PermittedChannelRequests session,forwarded-tcpip
567 match_cfg_line_group(const char *grps, int line, const char *user)
571 char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS];
575 * Even if we do not have a user yet, we still need to check for
578 arg = cp = xstrdup(grps);
579 while ((p = strsep(&cp, ",")) != NULL && *p != '\0') {
580 if (ngrps >= MAX_MATCH_GROUPS) {
581 error("line %d: too many groups in Match Group", line);
585 grplist[ngrps++] = p;
591 if ((pw = getpwnam(user)) == NULL) {
592 debug("Can't match group at line %d because user %.100s does "
593 "not exist", line, user);
594 } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
595 debug("Can't Match group because user %.100s not in any group "
596 "at line %d", user, line);
597 } else if (ga_match(grplist, ngrps) != 1) {
598 debug("user %.100s does not match group %.100s at line %d",
601 debug("user %.100s matched group %.100s at line %d", user,
612 match_cfg_line(char **condition, int line, const char *user, const char *host,
616 char *arg, *attrib, *cp = *condition;
620 debug3("checking syntax for 'Match %s'", cp);
622 debug3("checking match for '%s' user %s host %s addr %s", cp,
623 user ? user : "(null)", host ? host : "(null)",
624 address ? address : "(null)");
626 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
627 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
628 error("Missing Match criteria for %s", attrib);
632 if (strcasecmp(attrib, "user") == 0) {
637 if (match_pattern_list(user, arg, len, 0) != 1)
640 debug("user %.100s matched 'User %.100s' at "
641 "line %d", user, arg, line);
642 } else if (strcasecmp(attrib, "group") == 0) {
643 switch (match_cfg_line_group(arg, line, user)) {
649 } else if (strcasecmp(attrib, "host") == 0) {
654 if (match_hostname(host, arg, len) != 1)
657 debug("connection from %.100s matched 'Host "
658 "%.100s' at line %d", host, arg, line);
659 } else if (strcasecmp(attrib, "address") == 0) {
660 debug("address '%s' arg '%s'", address, arg);
665 if (match_hostname(address, arg, len) != 1)
668 debug("connection from %.100s matched 'Address "
669 "%.100s' at line %d", address, arg, line);
671 error("Unsupported Match attribute %s", attrib);
676 debug3("match %sfound", result ? "" : "not ");
681 #define WHITESPACE " \t\r\n"
684 process_server_config_line(ServerOptions *options, char *line,
685 const char *filename, int linenum, int *activep, const char *user,
686 const char *host, const char *address)
688 char *cp, **charptr, *arg, *p;
689 int cmdline = 0, *intptr, value, n;
690 ServerOpCodes opcode;
696 if ((arg = strdelim(&cp)) == NULL)
698 /* Ignore leading whitespace */
701 if (!arg || !*arg || *arg == '#')
705 opcode = parse_token(arg, filename, linenum, &flags);
707 if (activep == NULL) { /* We are processing a command line directive */
711 if (*activep && opcode != sMatch)
712 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
713 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
715 fatal("%s line %d: Directive '%s' is not allowed "
716 "within a Match block", filename, linenum, arg);
717 } else { /* this is a directive we have already processed */
725 /* Portable-specific options */
727 intptr = &options->use_pam;
730 /* Standard Options */
734 /* ignore ports from configfile if cmdline specifies ports */
735 if (options->ports_from_cmdline)
737 if (options->listen_addrs != NULL)
738 fatal("%s line %d: ports must be specified before "
739 "ListenAddress.", filename, linenum);
740 if (options->num_ports >= MAX_PORTS)
741 fatal("%s line %d: too many ports.",
744 if (!arg || *arg == '\0')
745 fatal("%s line %d: missing port number.",
747 options->ports[options->num_ports++] = a2port(arg);
748 if (options->ports[options->num_ports-1] == 0)
749 fatal("%s line %d: Badly formatted port number.",
754 intptr = &options->server_key_bits;
757 if (!arg || *arg == '\0')
758 fatal("%s line %d: missing integer value.",
761 if (*activep && *intptr == -1)
765 case sLoginGraceTime:
766 intptr = &options->login_grace_time;
769 if (!arg || *arg == '\0')
770 fatal("%s line %d: missing time value.",
772 if ((value = convtime(arg)) == -1)
773 fatal("%s line %d: invalid time value.",
779 case sKeyRegenerationTime:
780 intptr = &options->key_regeneration_time;
785 if (arg == NULL || *arg == '\0')
786 fatal("%s line %d: missing address",
788 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
789 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
790 && strchr(p+1, ':') != NULL) {
791 add_listen_addr(options, arg, 0);
796 fatal("%s line %d: bad address:port usage",
798 p = cleanhostname(p);
801 else if ((port = a2port(arg)) == 0)
802 fatal("%s line %d: bad port number", filename, linenum);
804 add_listen_addr(options, p, port);
810 if (!arg || *arg == '\0')
811 fatal("%s line %d: missing address family.",
813 intptr = &options->address_family;
814 if (options->listen_addrs != NULL)
815 fatal("%s line %d: address family must be specified before "
816 "ListenAddress.", filename, linenum);
817 if (strcasecmp(arg, "inet") == 0)
819 else if (strcasecmp(arg, "inet6") == 0)
821 else if (strcasecmp(arg, "any") == 0)
824 fatal("%s line %d: unsupported address family \"%s\".",
825 filename, linenum, arg);
831 intptr = &options->num_host_key_files;
832 if (*intptr >= MAX_HOSTKEYS)
833 fatal("%s line %d: too many host keys specified (max %d).",
834 filename, linenum, MAX_HOSTKEYS);
835 charptr = &options->host_key_files[*intptr];
838 if (!arg || *arg == '\0')
839 fatal("%s line %d: missing file name.",
841 if (*activep && *charptr == NULL) {
842 *charptr = tilde_expand_filename(arg, getuid());
843 /* increase optional counter */
845 *intptr = *intptr + 1;
850 charptr = &options->pid_file;
853 case sPermitRootLogin:
854 intptr = &options->permit_root_login;
856 if (!arg || *arg == '\0')
857 fatal("%s line %d: missing yes/"
858 "without-password/forced-commands-only/no "
859 "argument.", filename, linenum);
860 value = 0; /* silence compiler */
861 if (strcmp(arg, "without-password") == 0)
862 value = PERMIT_NO_PASSWD;
863 else if (strcmp(arg, "forced-commands-only") == 0)
864 value = PERMIT_FORCED_ONLY;
865 else if (strcmp(arg, "yes") == 0)
867 else if (strcmp(arg, "no") == 0)
870 fatal("%s line %d: Bad yes/"
871 "without-password/forced-commands-only/no "
872 "argument: %s", filename, linenum, arg);
878 intptr = &options->ignore_rhosts;
881 if (!arg || *arg == '\0')
882 fatal("%s line %d: missing yes/no argument.",
884 value = 0; /* silence compiler */
885 if (strcmp(arg, "yes") == 0)
887 else if (strcmp(arg, "no") == 0)
890 fatal("%s line %d: Bad yes/no argument: %s",
891 filename, linenum, arg);
892 if (*activep && *intptr == -1)
897 intptr = &options->none_enabled;
901 intptr = &options->tcp_rcv_buf_poll;
905 intptr = &options->hpn_disabled;
909 intptr = &options->hpn_buffer_size;
912 case sIgnoreUserKnownHosts:
913 intptr = &options->ignore_user_known_hosts;
916 case sRhostsRSAAuthentication:
917 intptr = &options->rhosts_rsa_authentication;
920 case sHostbasedAuthentication:
921 intptr = &options->hostbased_authentication;
924 case sHostbasedUsesNameFromPacketOnly:
925 intptr = &options->hostbased_uses_name_from_packet_only;
928 case sRSAAuthentication:
929 intptr = &options->rsa_authentication;
932 case sPubkeyAuthentication:
933 intptr = &options->pubkey_authentication;
936 case sKerberosAuthentication:
937 intptr = &options->kerberos_authentication;
940 case sKerberosOrLocalPasswd:
941 intptr = &options->kerberos_or_local_passwd;
944 case sKerberosTicketCleanup:
945 intptr = &options->kerberos_ticket_cleanup;
948 case sKerberosGetAFSToken:
949 intptr = &options->kerberos_get_afs_token;
952 case sGssAuthentication:
953 intptr = &options->gss_authentication;
957 intptr = &options->gss_keyex;
960 case sGssCleanupCreds:
961 intptr = &options->gss_cleanup_creds;
965 charptr = &options->gss_creds_path;
968 case sGssStrictAcceptor:
969 intptr = &options->gss_strict_acceptor;
972 case sGsiAllowLimitedProxy:
973 intptr = &options->gsi_allow_limited_proxy;
977 case sAllowSessionHooks:
978 intptr = &options->session_hooks_allow;
980 case sSessionHookStartupCmd:
981 case sSessionHookShutdownCmd:
983 if (!arg || *arg == '\0')
984 fatal("%s line %d: empty session hook command",
986 if (opcode==sSessionHookStartupCmd)
987 options->session_hooks_startup_cmd = strdup(arg);
989 options->session_hooks_shutdown_cmd = strdup(arg);
993 case sPasswordAuthentication:
994 intptr = &options->password_authentication;
997 case sKbdInteractiveAuthentication:
998 intptr = &options->kbd_interactive_authentication;
1001 case sChallengeResponseAuthentication:
1002 intptr = &options->challenge_response_authentication;
1006 intptr = &options->print_motd;
1010 intptr = &options->print_lastlog;
1013 case sX11Forwarding:
1014 intptr = &options->x11_forwarding;
1017 case sX11DisplayOffset:
1018 intptr = &options->x11_display_offset;
1021 case sX11UseLocalhost:
1022 intptr = &options->x11_use_localhost;
1025 case sXAuthLocation:
1026 charptr = &options->xauth_location;
1027 goto parse_filename;
1030 intptr = &options->strict_modes;
1034 intptr = &options->tcp_keep_alive;
1038 intptr = &options->permit_empty_passwd;
1041 case sPermitUserEnvironment:
1042 intptr = &options->permit_user_env;
1046 intptr = &options->use_login;
1050 intptr = &options->compression;
1051 arg = strdelim(&cp);
1052 if (!arg || *arg == '\0')
1053 fatal("%s line %d: missing yes/no/delayed "
1054 "argument.", filename, linenum);
1055 value = 0; /* silence compiler */
1056 if (strcmp(arg, "delayed") == 0)
1057 value = COMP_DELAYED;
1058 else if (strcmp(arg, "yes") == 0)
1060 else if (strcmp(arg, "no") == 0)
1063 fatal("%s line %d: Bad yes/no/delayed "
1064 "argument: %s", filename, linenum, arg);
1070 intptr = &options->gateway_ports;
1071 arg = strdelim(&cp);
1072 if (!arg || *arg == '\0')
1073 fatal("%s line %d: missing yes/no/clientspecified "
1074 "argument.", filename, linenum);
1075 value = 0; /* silence compiler */
1076 if (strcmp(arg, "clientspecified") == 0)
1078 else if (strcmp(arg, "yes") == 0)
1080 else if (strcmp(arg, "no") == 0)
1083 fatal("%s line %d: Bad yes/no/clientspecified "
1084 "argument: %s", filename, linenum, arg);
1090 intptr = &options->use_dns;
1094 intptr = (int *) &options->log_facility;
1095 arg = strdelim(&cp);
1096 value = log_facility_number(arg);
1097 if (value == SYSLOG_FACILITY_NOT_SET)
1098 fatal("%.200s line %d: unsupported log facility '%s'",
1099 filename, linenum, arg ? arg : "<NONE>");
1101 *intptr = (SyslogFacility) value;
1105 intptr = (int *) &options->log_level;
1106 arg = strdelim(&cp);
1107 value = log_level_number(arg);
1108 if (value == SYSLOG_LEVEL_NOT_SET)
1109 fatal("%.200s line %d: unsupported log level '%s'",
1110 filename, linenum, arg ? arg : "<NONE>");
1112 *intptr = (LogLevel) value;
1115 case sAllowTcpForwarding:
1116 intptr = &options->allow_tcp_forwarding;
1119 case sUsePrivilegeSeparation:
1120 intptr = &use_privsep;
1124 while ((arg = strdelim(&cp)) && *arg != '\0') {
1125 if (options->num_allow_users >= MAX_ALLOW_USERS)
1126 fatal("%s line %d: too many allow users.",
1128 options->allow_users[options->num_allow_users++] =
1134 while ((arg = strdelim(&cp)) && *arg != '\0') {
1135 if (options->num_deny_users >= MAX_DENY_USERS)
1136 fatal("%s line %d: too many deny users.",
1138 options->deny_users[options->num_deny_users++] =
1144 while ((arg = strdelim(&cp)) && *arg != '\0') {
1145 if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
1146 fatal("%s line %d: too many allow groups.",
1148 options->allow_groups[options->num_allow_groups++] =
1154 while ((arg = strdelim(&cp)) && *arg != '\0') {
1155 if (options->num_deny_groups >= MAX_DENY_GROUPS)
1156 fatal("%s line %d: too many deny groups.",
1158 options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
1163 arg = strdelim(&cp);
1164 if (!arg || *arg == '\0')
1165 fatal("%s line %d: Missing argument.", filename, linenum);
1166 if (!ciphers_valid(arg))
1167 fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1168 filename, linenum, arg ? arg : "<NONE>");
1169 if (options->ciphers == NULL)
1170 options->ciphers = xstrdup(arg);
1174 arg = strdelim(&cp);
1175 if (!arg || *arg == '\0')
1176 fatal("%s line %d: Missing argument.", filename, linenum);
1177 if (!mac_valid(arg))
1178 fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1179 filename, linenum, arg ? arg : "<NONE>");
1180 if (options->macs == NULL)
1181 options->macs = xstrdup(arg);
1185 intptr = &options->protocol;
1186 arg = strdelim(&cp);
1187 if (!arg || *arg == '\0')
1188 fatal("%s line %d: Missing argument.", filename, linenum);
1189 value = proto_spec(arg);
1190 if (value == SSH_PROTO_UNKNOWN)
1191 fatal("%s line %d: Bad protocol spec '%s'.",
1192 filename, linenum, arg ? arg : "<NONE>");
1193 if (*intptr == SSH_PROTO_UNKNOWN)
1198 if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1199 fatal("%s line %d: too many subsystems defined.",
1202 arg = strdelim(&cp);
1203 if (!arg || *arg == '\0')
1204 fatal("%s line %d: Missing subsystem name.",
1207 arg = strdelim(&cp);
1210 for (i = 0; i < options->num_subsystems; i++)
1211 if (strcmp(arg, options->subsystem_name[i]) == 0)
1212 fatal("%s line %d: Subsystem '%s' already defined.",
1213 filename, linenum, arg);
1214 options->subsystem_name[options->num_subsystems] = xstrdup(arg);
1215 arg = strdelim(&cp);
1216 if (!arg || *arg == '\0')
1217 fatal("%s line %d: Missing subsystem command.",
1219 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1221 /* Collect arguments (separate to executable) */
1223 len = strlen(p) + 1;
1224 while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1225 len += 1 + strlen(arg);
1226 p = xrealloc(p, 1, len);
1227 strlcat(p, " ", len);
1228 strlcat(p, arg, len);
1230 options->subsystem_args[options->num_subsystems] = p;
1231 options->num_subsystems++;
1235 arg = strdelim(&cp);
1236 if (!arg || *arg == '\0')
1237 fatal("%s line %d: Missing MaxStartups spec.",
1239 if ((n = sscanf(arg, "%d:%d:%d",
1240 &options->max_startups_begin,
1241 &options->max_startups_rate,
1242 &options->max_startups)) == 3) {
1243 if (options->max_startups_begin >
1244 options->max_startups ||
1245 options->max_startups_rate > 100 ||
1246 options->max_startups_rate < 1)
1247 fatal("%s line %d: Illegal MaxStartups spec.",
1250 fatal("%s line %d: Illegal MaxStartups spec.",
1253 options->max_startups = options->max_startups_begin;
1257 intptr = &options->max_authtries;
1261 charptr = &options->banner;
1262 goto parse_filename;
1264 * These options can contain %X options expanded at
1265 * connect time, so that you can specify paths like:
1267 * AuthorizedKeysFile /etc/ssh_keys/%u
1269 case sAuthorizedKeysFile:
1270 case sAuthorizedKeysFile2:
1271 charptr = (opcode == sAuthorizedKeysFile) ?
1272 &options->authorized_keys_file :
1273 &options->authorized_keys_file2;
1274 goto parse_filename;
1276 case sClientAliveInterval:
1277 intptr = &options->client_alive_interval;
1280 case sClientAliveCountMax:
1281 intptr = &options->client_alive_count_max;
1285 while ((arg = strdelim(&cp)) && *arg != '\0') {
1286 if (strchr(arg, '=') != NULL)
1287 fatal("%s line %d: Invalid environment name.",
1289 if (options->num_accept_env >= MAX_ACCEPT_ENV)
1290 fatal("%s line %d: too many allow env.",
1294 options->accept_env[options->num_accept_env++] =
1300 intptr = &options->permit_tun;
1301 arg = strdelim(&cp);
1302 if (!arg || *arg == '\0')
1303 fatal("%s line %d: Missing yes/point-to-point/"
1304 "ethernet/no argument.", filename, linenum);
1305 value = 0; /* silence compiler */
1306 if (strcasecmp(arg, "ethernet") == 0)
1307 value = SSH_TUNMODE_ETHERNET;
1308 else if (strcasecmp(arg, "point-to-point") == 0)
1309 value = SSH_TUNMODE_POINTOPOINT;
1310 else if (strcasecmp(arg, "yes") == 0)
1311 value = SSH_TUNMODE_YES;
1312 else if (strcasecmp(arg, "no") == 0)
1313 value = SSH_TUNMODE_NO;
1315 fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1316 "no argument: %s", filename, linenum, arg);
1323 fatal("Match directive not supported as a command-line "
1325 value = match_cfg_line(&cp, linenum, user, host, address);
1327 fatal("%s line %d: Bad Match condition", filename,
1333 arg = strdelim(&cp);
1334 if (!arg || *arg == '\0')
1335 fatal("%s line %d: missing PermitOpen specification",
1337 if (strcmp(arg, "any") == 0) {
1339 channel_clear_adm_permitted_opens();
1340 options->num_permitted_opens = 0;
1344 for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1347 fatal("%s line %d: missing host in PermitOpen",
1349 p = cleanhostname(p);
1350 if (arg == NULL || (port = a2port(arg)) == 0)
1351 fatal("%s line %d: bad port number in "
1352 "PermitOpen", filename, linenum);
1353 if (*activep && options->num_permitted_opens == -1) {
1354 channel_clear_adm_permitted_opens();
1355 options->num_permitted_opens =
1356 channel_add_adm_permitted_opens(p, port);
1363 fatal("%.200s line %d: Missing argument.", filename,
1365 len = strspn(cp, WHITESPACE);
1366 if (*activep && options->adm_forced_command == NULL)
1367 options->adm_forced_command = xstrdup(cp + len);
1371 logit("%s line %d: Deprecated option %s",
1372 filename, linenum, arg);
1374 arg = strdelim(&cp);
1378 logit("%s line %d: Unsupported option %s",
1379 filename, linenum, arg);
1381 arg = strdelim(&cp);
1385 fatal("%s line %d: Missing handler for opcode %s (%d)",
1386 filename, linenum, arg, opcode);
1388 if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
1389 fatal("%s line %d: garbage at end of line; \"%.200s\".",
1390 filename, linenum, arg);
1394 /* Reads the server configuration file. */
1397 load_server_config(const char *filename, Buffer *conf)
1399 char line[1024], *cp;
1402 debug2("%s: filename %s", __func__, filename);
1403 if ((f = fopen(filename, "r")) == NULL) {
1408 while (fgets(line, sizeof(line), f)) {
1410 * Trim out comments and strip whitespace
1411 * NB - preserve newlines, they are needed to reproduce
1412 * line numbers later for error messages
1414 if ((cp = strchr(line, '#')) != NULL)
1415 memcpy(cp, "\n", 2);
1416 cp = line + strspn(line, " \t\r");
1418 buffer_append(conf, cp, strlen(cp));
1420 buffer_append(conf, "\0", 1);
1422 debug2("%s: done config len = %d", __func__, buffer_len(conf));
1426 parse_server_match_config(ServerOptions *options, const char *user,
1427 const char *host, const char *address)
1431 initialize_server_options(&mo);
1432 parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
1433 copy_set_server_options(options, &mo);
1436 /* Copy any (supported) values that are set */
1438 copy_set_server_options(ServerOptions *dst, ServerOptions *src)
1440 if (src->allow_tcp_forwarding != -1)
1441 dst->allow_tcp_forwarding = src->allow_tcp_forwarding;
1442 if (src->gateway_ports != -1)
1443 dst->gateway_ports = src->gateway_ports;
1444 if (src->adm_forced_command != NULL) {
1445 if (dst->adm_forced_command != NULL)
1446 xfree(dst->adm_forced_command);
1447 dst->adm_forced_command = src->adm_forced_command;
1449 if (src->x11_display_offset != -1)
1450 dst->x11_display_offset = src->x11_display_offset;
1451 if (src->x11_forwarding != -1)
1452 dst->x11_forwarding = src->x11_forwarding;
1453 if (src->x11_use_localhost != -1)
1454 dst->x11_use_localhost = src->x11_use_localhost;
1458 parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1459 const char *user, const char *host, const char *address)
1461 int active, linenum, bad_options = 0;
1462 char *cp, *obuf, *cbuf;
1464 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1466 obuf = cbuf = xstrdup(buffer_ptr(conf));
1467 active = user ? 0 : 1;
1469 while ((cp = strsep(&cbuf, "\n")) != NULL) {
1470 if (process_server_config_line(options, cp, filename,
1471 linenum++, &active, user, host, address) != 0)
1475 if (bad_options > 0)
1476 fatal("%s: terminating, %d bad configuration options",
1477 filename, bad_options);