MFC if_ethersubr.c rev1.77:
[dragonfly.git] / crypto / openssh-5 / servconf.c
blobb7211c9299011d4c597afdd0f877371d68e17db8
1 /* $OpenBSD: servconf.c,v 1.177 2008/02/10 10:54:28 djm Exp $ */
2 /*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
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".
13 #include "includes.h"
15 #include <sys/types.h>
16 #include <sys/socket.h>
18 #include <netdb.h>
19 #include <pwd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <stdarg.h>
27 #include "xmalloc.h"
28 #include "ssh.h"
29 #include "log.h"
30 #include "buffer.h"
31 #include "servconf.h"
32 #include "compat.h"
33 #include "pathnames.h"
34 #include "misc.h"
35 #include "cipher.h"
36 #include "key.h"
37 #include "kex.h"
38 #include "mac.h"
39 #include "match.h"
40 #include "channels.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;
48 extern Buffer cfg;
50 /* Initializes the server options to their default values. */
52 void
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;
91 options->kerberos_get_afs_token = -1;
92 options->gss_authentication=-1;
93 options->gss_cleanup_creds = -1;
94 options->password_authentication = -1;
95 options->kbd_interactive_authentication = -1;
96 options->challenge_response_authentication = -1;
97 options->permit_blacklisted_keys = -1;
98 options->permit_empty_passwd = -1;
99 options->permit_user_env = -1;
100 options->use_login = -1;
101 options->compression = -1;
102 options->allow_tcp_forwarding = -1;
103 options->num_allow_users = 0;
104 options->num_deny_users = 0;
105 options->num_allow_groups = 0;
106 options->num_deny_groups = 0;
107 options->ciphers = NULL;
108 options->macs = NULL;
109 options->protocol = SSH_PROTO_UNKNOWN;
110 options->gateway_ports = -1;
111 options->num_subsystems = 0;
112 options->max_startups_begin = -1;
113 options->max_startups_rate = -1;
114 options->max_startups = -1;
115 options->max_authtries = -1;
116 options->banner = NULL;
117 options->use_dns = -1;
118 options->client_alive_interval = -1;
119 options->client_alive_count_max = -1;
120 options->authorized_keys_file = NULL;
121 options->authorized_keys_file2 = NULL;
122 options->num_accept_env = 0;
123 options->permit_tun = -1;
124 options->num_permitted_opens = -1;
125 options->adm_forced_command = NULL;
126 options->chroot_directory = NULL;
129 void
130 fill_default_server_options(ServerOptions *options)
132 /* Portable-specific options */
133 if (options->use_pam == -1)
134 options->use_pam = 0;
136 /* Standard Options */
137 if (options->protocol == SSH_PROTO_UNKNOWN)
138 options->protocol = SSH_PROTO_2;
139 if (options->num_host_key_files == 0) {
140 /* fill default hostkeys for protocols */
141 if (options->protocol & SSH_PROTO_1)
142 options->host_key_files[options->num_host_key_files++] =
143 _PATH_HOST_KEY_FILE;
144 if (options->protocol & SSH_PROTO_2) {
145 options->host_key_files[options->num_host_key_files++] =
146 _PATH_HOST_DSA_KEY_FILE;
149 if (options->num_ports == 0)
150 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
151 if (options->listen_addrs == NULL)
152 add_listen_addr(options, NULL, 0);
153 if (options->pid_file == NULL)
154 options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
155 if (options->server_key_bits == -1)
156 options->server_key_bits = 768;
157 if (options->login_grace_time == -1)
158 options->login_grace_time = 120;
159 if (options->key_regeneration_time == -1)
160 options->key_regeneration_time = 3600;
161 if (options->permit_root_login == PERMIT_NOT_SET)
162 options->permit_root_login = PERMIT_NO;
163 if (options->ignore_rhosts == -1)
164 options->ignore_rhosts = 1;
165 if (options->ignore_user_known_hosts == -1)
166 options->ignore_user_known_hosts = 0;
167 if (options->print_motd == -1)
168 options->print_motd = 1;
169 if (options->print_lastlog == -1)
170 options->print_lastlog = 1;
171 if (options->x11_forwarding == -1)
172 options->x11_forwarding = 1;
173 if (options->x11_display_offset == -1)
174 options->x11_display_offset = 10;
175 if (options->x11_use_localhost == -1)
176 options->x11_use_localhost = 1;
177 if (options->xauth_location == NULL)
178 options->xauth_location = _PATH_XAUTH;
179 if (options->strict_modes == -1)
180 options->strict_modes = 1;
181 if (options->tcp_keep_alive == -1)
182 options->tcp_keep_alive = 1;
183 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
184 options->log_facility = SYSLOG_FACILITY_AUTH;
185 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
186 options->log_level = SYSLOG_LEVEL_INFO;
187 if (options->rhosts_rsa_authentication == -1)
188 options->rhosts_rsa_authentication = 0;
189 if (options->hostbased_authentication == -1)
190 options->hostbased_authentication = 0;
191 if (options->hostbased_uses_name_from_packet_only == -1)
192 options->hostbased_uses_name_from_packet_only = 0;
193 if (options->rsa_authentication == -1)
194 options->rsa_authentication = 1;
195 if (options->pubkey_authentication == -1)
196 options->pubkey_authentication = 1;
197 if (options->kerberos_authentication == -1)
198 options->kerberos_authentication = 0;
199 if (options->kerberos_or_local_passwd == -1)
200 options->kerberos_or_local_passwd = 1;
201 if (options->kerberos_ticket_cleanup == -1)
202 options->kerberos_ticket_cleanup = 1;
203 if (options->kerberos_get_afs_token == -1)
204 options->kerberos_get_afs_token = 0;
205 if (options->gss_authentication == -1)
206 options->gss_authentication = 0;
207 if (options->gss_cleanup_creds == -1)
208 options->gss_cleanup_creds = 1;
209 if (options->password_authentication == -1)
210 options->password_authentication = 1;
211 if (options->kbd_interactive_authentication == -1)
212 options->kbd_interactive_authentication = 0;
213 if (options->challenge_response_authentication == -1)
214 options->challenge_response_authentication = 1;
215 if (options->permit_blacklisted_keys == -1)
216 options->permit_blacklisted_keys = 0;
217 if (options->permit_empty_passwd == -1)
218 options->permit_empty_passwd = 0;
219 if (options->permit_user_env == -1)
220 options->permit_user_env = 0;
221 if (options->use_login == -1)
222 options->use_login = 0;
223 if (options->compression == -1)
224 options->compression = COMP_DELAYED;
225 if (options->allow_tcp_forwarding == -1)
226 options->allow_tcp_forwarding = 1;
227 if (options->gateway_ports == -1)
228 options->gateway_ports = 0;
229 if (options->max_startups == -1)
230 options->max_startups = 10;
231 if (options->max_startups_rate == -1)
232 options->max_startups_rate = 100; /* 100% */
233 if (options->max_startups_begin == -1)
234 options->max_startups_begin = options->max_startups;
235 if (options->max_authtries == -1)
236 options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
237 if (options->use_dns == -1)
238 options->use_dns = 1;
239 if (options->client_alive_interval == -1)
240 options->client_alive_interval = 0;
241 if (options->client_alive_count_max == -1)
242 options->client_alive_count_max = 3;
243 if (options->authorized_keys_file2 == NULL) {
244 /* authorized_keys_file2 falls back to authorized_keys_file */
245 if (options->authorized_keys_file != NULL)
246 options->authorized_keys_file2 = options->authorized_keys_file;
247 else
248 options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
250 if (options->authorized_keys_file == NULL)
251 options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
252 if (options->permit_tun == -1)
253 options->permit_tun = SSH_TUNMODE_NO;
255 /* Turn privilege separation on by default */
256 if (use_privsep == -1)
257 use_privsep = 1;
259 #ifndef HAVE_MMAP
260 if (use_privsep && options->compression == 1) {
261 error("This platform does not support both privilege "
262 "separation and compression");
263 error("Compression disabled");
264 options->compression = 0;
266 #endif
270 /* Keyword tokens. */
271 typedef enum {
272 sBadOption, /* == unknown option */
273 /* Portable-specific options */
274 sUsePAM,
275 /* Standard Options */
276 sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
277 sPermitRootLogin, sLogFacility, sLogLevel,
278 sRhostsRSAAuthentication, sRSAAuthentication,
279 sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
280 sKerberosGetAFSToken,
281 sKerberosTgtPassing, sChallengeResponseAuthentication,
282 sPasswordAuthentication, sKbdInteractiveAuthentication,
283 sListenAddress, sAddressFamily,
284 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
285 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
286 sStrictModes, sPermitBlacklistedKeys, sEmptyPasswd, sTCPKeepAlive,
287 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
288 sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
289 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
290 sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
291 sMaxStartups, sMaxAuthTries,
292 sBanner, sUseDNS, sHostbasedAuthentication,
293 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
294 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
295 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
296 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
297 sUsePrivilegeSeparation,
298 sVersionAddendum,
299 sDeprecated, sUnsupported
300 } ServerOpCodes;
302 #define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
303 #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
304 #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
306 /* Textual representation of the tokens. */
307 static struct {
308 const char *name;
309 ServerOpCodes opcode;
310 u_int flags;
311 } keywords[] = {
312 /* Portable-specific options */
313 #ifdef USE_PAM
314 { "usepam", sUsePAM, SSHCFG_GLOBAL },
315 #else
316 { "usepam", sUnsupported, SSHCFG_GLOBAL },
317 #endif
318 { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
319 /* Standard Options */
320 { "port", sPort, SSHCFG_GLOBAL },
321 { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
322 { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
323 { "pidfile", sPidFile, SSHCFG_GLOBAL },
324 { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
325 { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
326 { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
327 { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
328 { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
329 { "loglevel", sLogLevel, SSHCFG_GLOBAL },
330 { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
331 { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
332 { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
333 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
334 { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
335 { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
336 { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
337 #ifdef KRB5
338 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
339 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
340 { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
341 #ifdef USE_AFS
342 { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
343 #else
344 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
345 #endif
346 #else
347 { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
348 { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
349 { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
350 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
351 #endif
352 { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
353 { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
354 #ifdef GSSAPI
355 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
356 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
357 #else
358 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
359 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
360 #endif
361 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
362 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
363 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
364 { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
365 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
366 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
367 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
368 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
369 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
370 { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
371 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
372 { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
373 { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
374 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
375 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
376 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
377 { "permitblacklistedkeys", sPermitBlacklistedKeys, SSHCFG_GLOBAL },
378 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
379 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
380 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
381 { "compression", sCompression, SSHCFG_GLOBAL },
382 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
383 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
384 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
385 { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
386 { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
387 { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
388 { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
389 { "ciphers", sCiphers, SSHCFG_GLOBAL },
390 { "macs", sMacs, SSHCFG_GLOBAL },
391 { "protocol", sProtocol, SSHCFG_GLOBAL },
392 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
393 { "subsystem", sSubsystem, SSHCFG_GLOBAL },
394 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
395 { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
396 { "banner", sBanner, SSHCFG_ALL },
397 { "usedns", sUseDNS, SSHCFG_GLOBAL },
398 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
399 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
400 { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
401 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
402 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
403 { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
404 { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
405 { "versionaddendum", sVersionAddendum , SSHCFG_GLOBAL },
406 { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
407 { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
408 { "match", sMatch, SSHCFG_ALL },
409 { "permitopen", sPermitOpen, SSHCFG_ALL },
410 { "forcecommand", sForceCommand, SSHCFG_ALL },
411 { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
412 { NULL, sBadOption, 0 }
416 * Returns the number of the token pointed to by cp or sBadOption.
419 static ServerOpCodes
420 parse_token(const char *cp, const char *filename,
421 int linenum, u_int *flags)
423 u_int i;
425 for (i = 0; keywords[i].name; i++)
426 if (strcasecmp(cp, keywords[i].name) == 0) {
427 *flags = keywords[i].flags;
428 return keywords[i].opcode;
431 error("%s: line %d: Bad configuration option: %s",
432 filename, linenum, cp);
433 return sBadOption;
436 static void
437 add_listen_addr(ServerOptions *options, char *addr, u_short port)
439 u_int i;
441 if (options->num_ports == 0)
442 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
443 if (options->address_family == -1)
444 options->address_family = AF_UNSPEC;
445 if (port == 0)
446 for (i = 0; i < options->num_ports; i++)
447 add_one_listen_addr(options, addr, options->ports[i]);
448 else
449 add_one_listen_addr(options, addr, port);
452 static void
453 add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
455 struct addrinfo hints, *ai, *aitop;
456 char strport[NI_MAXSERV];
457 int gaierr;
459 memset(&hints, 0, sizeof(hints));
460 hints.ai_family = options->address_family;
461 hints.ai_socktype = SOCK_STREAM;
462 hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
463 snprintf(strport, sizeof strport, "%u", port);
464 if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
465 fatal("bad addr or host: %s (%s)",
466 addr ? addr : "<NULL>",
467 ssh_gai_strerror(gaierr));
468 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
470 ai->ai_next = options->listen_addrs;
471 options->listen_addrs = aitop;
475 * The strategy for the Match blocks is that the config file is parsed twice.
477 * The first time is at startup. activep is initialized to 1 and the
478 * directives in the global context are processed and acted on. Hitting a
479 * Match directive unsets activep and the directives inside the block are
480 * checked for syntax only.
482 * The second time is after a connection has been established but before
483 * authentication. activep is initialized to 2 and global config directives
484 * are ignored since they have already been processed. If the criteria in a
485 * Match block is met, activep is set and the subsequent directives
486 * processed and actioned until EOF or another Match block unsets it. Any
487 * options set are copied into the main server config.
489 * Potential additions/improvements:
490 * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
492 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
493 * Match Address 192.168.0.*
494 * Tag trusted
495 * Match Group wheel
496 * Tag trusted
497 * Match Tag trusted
498 * AllowTcpForwarding yes
499 * GatewayPorts clientspecified
500 * [...]
502 * - Add a PermittedChannelRequests directive
503 * Match Group shell
504 * PermittedChannelRequests session,forwarded-tcpip
507 static int
508 match_cfg_line_group(const char *grps, int line, const char *user)
510 int result = 0;
511 u_int ngrps = 0;
512 char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS];
513 struct passwd *pw;
516 * Even if we do not have a user yet, we still need to check for
517 * valid syntax.
519 arg = cp = xstrdup(grps);
520 while ((p = strsep(&cp, ",")) != NULL && *p != '\0') {
521 if (ngrps >= MAX_MATCH_GROUPS) {
522 error("line %d: too many groups in Match Group", line);
523 result = -1;
524 goto out;
526 grplist[ngrps++] = p;
529 if (user == NULL)
530 goto out;
532 if ((pw = getpwnam(user)) == NULL) {
533 debug("Can't match group at line %d because user %.100s does "
534 "not exist", line, user);
535 } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
536 debug("Can't Match group because user %.100s not in any group "
537 "at line %d", user, line);
538 } else if (ga_match(grplist, ngrps) != 1) {
539 debug("user %.100s does not match group %.100s at line %d",
540 user, arg, line);
541 } else {
542 debug("user %.100s matched group %.100s at line %d", user,
543 arg, line);
544 result = 1;
546 out:
547 ga_free();
548 xfree(arg);
549 return result;
552 static int
553 match_cfg_line(char **condition, int line, const char *user, const char *host,
554 const char *address)
556 int result = 1;
557 char *arg, *attrib, *cp = *condition;
558 size_t len;
560 if (user == NULL)
561 debug3("checking syntax for 'Match %s'", cp);
562 else
563 debug3("checking match for '%s' user %s host %s addr %s", cp,
564 user ? user : "(null)", host ? host : "(null)",
565 address ? address : "(null)");
567 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
568 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
569 error("Missing Match criteria for %s", attrib);
570 return -1;
572 len = strlen(arg);
573 if (strcasecmp(attrib, "user") == 0) {
574 if (!user) {
575 result = 0;
576 continue;
578 if (match_pattern_list(user, arg, len, 0) != 1)
579 result = 0;
580 else
581 debug("user %.100s matched 'User %.100s' at "
582 "line %d", user, arg, line);
583 } else if (strcasecmp(attrib, "group") == 0) {
584 switch (match_cfg_line_group(arg, line, user)) {
585 case -1:
586 return -1;
587 case 0:
588 result = 0;
590 } else if (strcasecmp(attrib, "host") == 0) {
591 if (!host) {
592 result = 0;
593 continue;
595 if (match_hostname(host, arg, len) != 1)
596 result = 0;
597 else
598 debug("connection from %.100s matched 'Host "
599 "%.100s' at line %d", host, arg, line);
600 } else if (strcasecmp(attrib, "address") == 0) {
601 if (!address) {
602 result = 0;
603 continue;
605 if (match_hostname(address, arg, len) != 1)
606 result = 0;
607 else
608 debug("connection from %.100s matched 'Address "
609 "%.100s' at line %d", address, arg, line);
610 } else {
611 error("Unsupported Match attribute %s", attrib);
612 return -1;
615 if (user != NULL)
616 debug3("match %sfound", result ? "" : "not ");
617 *condition = cp;
618 return result;
621 #define WHITESPACE " \t\r\n"
624 process_server_config_line(ServerOptions *options, char *line,
625 const char *filename, int linenum, int *activep, const char *user,
626 const char *host, const char *address)
628 char *cp, **charptr, *arg, *p;
629 int cmdline = 0, *intptr, value, n;
630 SyslogFacility *log_facility_ptr;
631 LogLevel *log_level_ptr;
632 ServerOpCodes opcode;
633 u_short port;
634 u_int i, flags = 0;
635 size_t len;
637 cp = line;
638 if ((arg = strdelim(&cp)) == NULL)
639 return 0;
640 /* Ignore leading whitespace */
641 if (*arg == '\0')
642 arg = strdelim(&cp);
643 if (!arg || !*arg || *arg == '#')
644 return 0;
645 intptr = NULL;
646 charptr = NULL;
647 opcode = parse_token(arg, filename, linenum, &flags);
649 if (activep == NULL) { /* We are processing a command line directive */
650 cmdline = 1;
651 activep = &cmdline;
653 if (*activep && opcode != sMatch)
654 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
655 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
656 if (user == NULL) {
657 fatal("%s line %d: Directive '%s' is not allowed "
658 "within a Match block", filename, linenum, arg);
659 } else { /* this is a directive we have already processed */
660 while (arg)
661 arg = strdelim(&cp);
662 return 0;
666 switch (opcode) {
667 /* Portable-specific options */
668 case sUsePAM:
669 intptr = &options->use_pam;
670 goto parse_flag;
672 /* Standard Options */
673 case sBadOption:
674 return -1;
675 case sPort:
676 /* ignore ports from configfile if cmdline specifies ports */
677 if (options->ports_from_cmdline)
678 return 0;
679 if (options->listen_addrs != NULL)
680 fatal("%s line %d: ports must be specified before "
681 "ListenAddress.", filename, linenum);
682 if (options->num_ports >= MAX_PORTS)
683 fatal("%s line %d: too many ports.",
684 filename, linenum);
685 arg = strdelim(&cp);
686 if (!arg || *arg == '\0')
687 fatal("%s line %d: missing port number.",
688 filename, linenum);
689 options->ports[options->num_ports++] = a2port(arg);
690 if (options->ports[options->num_ports-1] == 0)
691 fatal("%s line %d: Badly formatted port number.",
692 filename, linenum);
693 break;
695 case sServerKeyBits:
696 intptr = &options->server_key_bits;
697 parse_int:
698 arg = strdelim(&cp);
699 if (!arg || *arg == '\0')
700 fatal("%s line %d: missing integer value.",
701 filename, linenum);
702 value = atoi(arg);
703 if (*activep && *intptr == -1)
704 *intptr = value;
705 break;
707 case sLoginGraceTime:
708 intptr = &options->login_grace_time;
709 parse_time:
710 arg = strdelim(&cp);
711 if (!arg || *arg == '\0')
712 fatal("%s line %d: missing time value.",
713 filename, linenum);
714 if ((value = convtime(arg)) == -1)
715 fatal("%s line %d: invalid time value.",
716 filename, linenum);
717 if (*intptr == -1)
718 *intptr = value;
719 break;
721 case sKeyRegenerationTime:
722 intptr = &options->key_regeneration_time;
723 goto parse_time;
725 case sListenAddress:
726 arg = strdelim(&cp);
727 if (arg == NULL || *arg == '\0')
728 fatal("%s line %d: missing address",
729 filename, linenum);
730 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
731 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
732 && strchr(p+1, ':') != NULL) {
733 add_listen_addr(options, arg, 0);
734 break;
736 p = hpdelim(&arg);
737 if (p == NULL)
738 fatal("%s line %d: bad address:port usage",
739 filename, linenum);
740 p = cleanhostname(p);
741 if (arg == NULL)
742 port = 0;
743 else if ((port = a2port(arg)) == 0)
744 fatal("%s line %d: bad port number", filename, linenum);
746 add_listen_addr(options, p, port);
748 break;
750 case sAddressFamily:
751 arg = strdelim(&cp);
752 if (!arg || *arg == '\0')
753 fatal("%s line %d: missing address family.",
754 filename, linenum);
755 intptr = &options->address_family;
756 if (options->listen_addrs != NULL)
757 fatal("%s line %d: address family must be specified before "
758 "ListenAddress.", filename, linenum);
759 if (strcasecmp(arg, "inet") == 0)
760 value = AF_INET;
761 else if (strcasecmp(arg, "inet6") == 0)
762 value = AF_INET6;
763 else if (strcasecmp(arg, "any") == 0)
764 value = AF_UNSPEC;
765 else
766 fatal("%s line %d: unsupported address family \"%s\".",
767 filename, linenum, arg);
768 if (*intptr == -1)
769 *intptr = value;
770 break;
772 case sHostKeyFile:
773 intptr = &options->num_host_key_files;
774 if (*intptr >= MAX_HOSTKEYS)
775 fatal("%s line %d: too many host keys specified (max %d).",
776 filename, linenum, MAX_HOSTKEYS);
777 charptr = &options->host_key_files[*intptr];
778 parse_filename:
779 arg = strdelim(&cp);
780 if (!arg || *arg == '\0')
781 fatal("%s line %d: missing file name.",
782 filename, linenum);
783 if (*activep && *charptr == NULL) {
784 *charptr = tilde_expand_filename(arg, getuid());
785 /* increase optional counter */
786 if (intptr != NULL)
787 *intptr = *intptr + 1;
789 break;
791 case sPidFile:
792 charptr = &options->pid_file;
793 goto parse_filename;
795 case sPermitRootLogin:
796 intptr = &options->permit_root_login;
797 arg = strdelim(&cp);
798 if (!arg || *arg == '\0')
799 fatal("%s line %d: missing yes/"
800 "without-password/forced-commands-only/no "
801 "argument.", filename, linenum);
802 value = 0; /* silence compiler */
803 if (strcmp(arg, "without-password") == 0)
804 value = PERMIT_NO_PASSWD;
805 else if (strcmp(arg, "forced-commands-only") == 0)
806 value = PERMIT_FORCED_ONLY;
807 else if (strcmp(arg, "yes") == 0)
808 value = PERMIT_YES;
809 else if (strcmp(arg, "no") == 0)
810 value = PERMIT_NO;
811 else
812 fatal("%s line %d: Bad yes/"
813 "without-password/forced-commands-only/no "
814 "argument: %s", filename, linenum, arg);
815 if (*activep && *intptr == -1)
816 *intptr = value;
817 break;
819 case sIgnoreRhosts:
820 intptr = &options->ignore_rhosts;
821 parse_flag:
822 arg = strdelim(&cp);
823 if (!arg || *arg == '\0')
824 fatal("%s line %d: missing yes/no argument.",
825 filename, linenum);
826 value = 0; /* silence compiler */
827 if (strcmp(arg, "yes") == 0)
828 value = 1;
829 else if (strcmp(arg, "no") == 0)
830 value = 0;
831 else
832 fatal("%s line %d: Bad yes/no argument: %s",
833 filename, linenum, arg);
834 if (*activep && *intptr == -1)
835 *intptr = value;
836 break;
838 case sIgnoreUserKnownHosts:
839 intptr = &options->ignore_user_known_hosts;
840 goto parse_flag;
842 case sRhostsRSAAuthentication:
843 intptr = &options->rhosts_rsa_authentication;
844 goto parse_flag;
846 case sHostbasedAuthentication:
847 intptr = &options->hostbased_authentication;
848 goto parse_flag;
850 case sHostbasedUsesNameFromPacketOnly:
851 intptr = &options->hostbased_uses_name_from_packet_only;
852 goto parse_flag;
854 case sRSAAuthentication:
855 intptr = &options->rsa_authentication;
856 goto parse_flag;
858 case sPubkeyAuthentication:
859 intptr = &options->pubkey_authentication;
860 goto parse_flag;
862 case sKerberosAuthentication:
863 intptr = &options->kerberos_authentication;
864 goto parse_flag;
866 case sKerberosOrLocalPasswd:
867 intptr = &options->kerberos_or_local_passwd;
868 goto parse_flag;
870 case sKerberosTicketCleanup:
871 intptr = &options->kerberos_ticket_cleanup;
872 goto parse_flag;
874 case sKerberosGetAFSToken:
875 intptr = &options->kerberos_get_afs_token;
876 goto parse_flag;
878 case sGssAuthentication:
879 intptr = &options->gss_authentication;
880 goto parse_flag;
882 case sGssCleanupCreds:
883 intptr = &options->gss_cleanup_creds;
884 goto parse_flag;
886 case sPasswordAuthentication:
887 intptr = &options->password_authentication;
888 goto parse_flag;
890 case sKbdInteractiveAuthentication:
891 intptr = &options->kbd_interactive_authentication;
892 goto parse_flag;
894 case sChallengeResponseAuthentication:
895 intptr = &options->challenge_response_authentication;
896 goto parse_flag;
898 case sPrintMotd:
899 intptr = &options->print_motd;
900 goto parse_flag;
902 case sPrintLastLog:
903 intptr = &options->print_lastlog;
904 goto parse_flag;
906 case sX11Forwarding:
907 intptr = &options->x11_forwarding;
908 goto parse_flag;
910 case sX11DisplayOffset:
911 intptr = &options->x11_display_offset;
912 goto parse_int;
914 case sX11UseLocalhost:
915 intptr = &options->x11_use_localhost;
916 goto parse_flag;
918 case sXAuthLocation:
919 charptr = &options->xauth_location;
920 goto parse_filename;
922 case sStrictModes:
923 intptr = &options->strict_modes;
924 goto parse_flag;
926 case sTCPKeepAlive:
927 intptr = &options->tcp_keep_alive;
928 goto parse_flag;
930 case sPermitBlacklistedKeys:
931 intptr = &options->permit_blacklisted_keys;
932 goto parse_flag;
934 case sEmptyPasswd:
935 intptr = &options->permit_empty_passwd;
936 goto parse_flag;
938 case sPermitUserEnvironment:
939 intptr = &options->permit_user_env;
940 goto parse_flag;
942 case sUseLogin:
943 intptr = &options->use_login;
944 goto parse_flag;
946 case sCompression:
947 intptr = &options->compression;
948 arg = strdelim(&cp);
949 if (!arg || *arg == '\0')
950 fatal("%s line %d: missing yes/no/delayed "
951 "argument.", filename, linenum);
952 value = 0; /* silence compiler */
953 if (strcmp(arg, "delayed") == 0)
954 value = COMP_DELAYED;
955 else if (strcmp(arg, "yes") == 0)
956 value = COMP_ZLIB;
957 else if (strcmp(arg, "no") == 0)
958 value = COMP_NONE;
959 else
960 fatal("%s line %d: Bad yes/no/delayed "
961 "argument: %s", filename, linenum, arg);
962 if (*intptr == -1)
963 *intptr = value;
964 break;
966 case sGatewayPorts:
967 intptr = &options->gateway_ports;
968 arg = strdelim(&cp);
969 if (!arg || *arg == '\0')
970 fatal("%s line %d: missing yes/no/clientspecified "
971 "argument.", filename, linenum);
972 value = 0; /* silence compiler */
973 if (strcmp(arg, "clientspecified") == 0)
974 value = 2;
975 else if (strcmp(arg, "yes") == 0)
976 value = 1;
977 else if (strcmp(arg, "no") == 0)
978 value = 0;
979 else
980 fatal("%s line %d: Bad yes/no/clientspecified "
981 "argument: %s", filename, linenum, arg);
982 if (*activep && *intptr == -1)
983 *intptr = value;
984 break;
986 case sUseDNS:
987 intptr = &options->use_dns;
988 goto parse_flag;
990 case sLogFacility:
991 log_facility_ptr = &options->log_facility;
992 arg = strdelim(&cp);
993 value = log_facility_number(arg);
994 if (value == SYSLOG_FACILITY_NOT_SET)
995 fatal("%.200s line %d: unsupported log facility '%s'",
996 filename, linenum, arg ? arg : "<NONE>");
997 if (*log_facility_ptr == -1)
998 *log_facility_ptr = (SyslogFacility) value;
999 break;
1001 case sLogLevel:
1002 log_level_ptr = &options->log_level;
1003 arg = strdelim(&cp);
1004 value = log_level_number(arg);
1005 if (value == SYSLOG_LEVEL_NOT_SET)
1006 fatal("%.200s line %d: unsupported log level '%s'",
1007 filename, linenum, arg ? arg : "<NONE>");
1008 if (*log_level_ptr == -1)
1009 *log_level_ptr = (LogLevel) value;
1010 break;
1012 case sAllowTcpForwarding:
1013 intptr = &options->allow_tcp_forwarding;
1014 goto parse_flag;
1016 case sUsePrivilegeSeparation:
1017 intptr = &use_privsep;
1018 goto parse_flag;
1020 case sAllowUsers:
1021 while ((arg = strdelim(&cp)) && *arg != '\0') {
1022 if (options->num_allow_users >= MAX_ALLOW_USERS)
1023 fatal("%s line %d: too many allow users.",
1024 filename, linenum);
1025 options->allow_users[options->num_allow_users++] =
1026 xstrdup(arg);
1028 break;
1030 case sDenyUsers:
1031 while ((arg = strdelim(&cp)) && *arg != '\0') {
1032 if (options->num_deny_users >= MAX_DENY_USERS)
1033 fatal("%s line %d: too many deny users.",
1034 filename, linenum);
1035 options->deny_users[options->num_deny_users++] =
1036 xstrdup(arg);
1038 break;
1040 case sAllowGroups:
1041 while ((arg = strdelim(&cp)) && *arg != '\0') {
1042 if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
1043 fatal("%s line %d: too many allow groups.",
1044 filename, linenum);
1045 options->allow_groups[options->num_allow_groups++] =
1046 xstrdup(arg);
1048 break;
1050 case sDenyGroups:
1051 while ((arg = strdelim(&cp)) && *arg != '\0') {
1052 if (options->num_deny_groups >= MAX_DENY_GROUPS)
1053 fatal("%s line %d: too many deny groups.",
1054 filename, linenum);
1055 options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
1057 break;
1059 case sCiphers:
1060 arg = strdelim(&cp);
1061 if (!arg || *arg == '\0')
1062 fatal("%s line %d: Missing argument.", filename, linenum);
1063 if (!ciphers_valid(arg))
1064 fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1065 filename, linenum, arg ? arg : "<NONE>");
1066 if (options->ciphers == NULL)
1067 options->ciphers = xstrdup(arg);
1068 break;
1070 case sMacs:
1071 arg = strdelim(&cp);
1072 if (!arg || *arg == '\0')
1073 fatal("%s line %d: Missing argument.", filename, linenum);
1074 if (!mac_valid(arg))
1075 fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1076 filename, linenum, arg ? arg : "<NONE>");
1077 if (options->macs == NULL)
1078 options->macs = xstrdup(arg);
1079 break;
1081 case sProtocol:
1082 intptr = &options->protocol;
1083 arg = strdelim(&cp);
1084 if (!arg || *arg == '\0')
1085 fatal("%s line %d: Missing argument.", filename, linenum);
1086 value = proto_spec(arg);
1087 if (value == SSH_PROTO_UNKNOWN)
1088 fatal("%s line %d: Bad protocol spec '%s'.",
1089 filename, linenum, arg ? arg : "<NONE>");
1090 if (*intptr == SSH_PROTO_UNKNOWN)
1091 *intptr = value;
1092 break;
1094 case sSubsystem:
1095 if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1096 fatal("%s line %d: too many subsystems defined.",
1097 filename, linenum);
1099 arg = strdelim(&cp);
1100 if (!arg || *arg == '\0')
1101 fatal("%s line %d: Missing subsystem name.",
1102 filename, linenum);
1103 if (!*activep) {
1104 arg = strdelim(&cp);
1105 break;
1107 for (i = 0; i < options->num_subsystems; i++)
1108 if (strcmp(arg, options->subsystem_name[i]) == 0)
1109 fatal("%s line %d: Subsystem '%s' already defined.",
1110 filename, linenum, arg);
1111 options->subsystem_name[options->num_subsystems] = xstrdup(arg);
1112 arg = strdelim(&cp);
1113 if (!arg || *arg == '\0')
1114 fatal("%s line %d: Missing subsystem command.",
1115 filename, linenum);
1116 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1118 /* Collect arguments (separate to executable) */
1119 p = xstrdup(arg);
1120 len = strlen(p) + 1;
1121 while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1122 len += 1 + strlen(arg);
1123 p = xrealloc(p, 1, len);
1124 strlcat(p, " ", len);
1125 strlcat(p, arg, len);
1127 options->subsystem_args[options->num_subsystems] = p;
1128 options->num_subsystems++;
1129 break;
1131 case sMaxStartups:
1132 arg = strdelim(&cp);
1133 if (!arg || *arg == '\0')
1134 fatal("%s line %d: Missing MaxStartups spec.",
1135 filename, linenum);
1136 if ((n = sscanf(arg, "%d:%d:%d",
1137 &options->max_startups_begin,
1138 &options->max_startups_rate,
1139 &options->max_startups)) == 3) {
1140 if (options->max_startups_begin >
1141 options->max_startups ||
1142 options->max_startups_rate > 100 ||
1143 options->max_startups_rate < 1)
1144 fatal("%s line %d: Illegal MaxStartups spec.",
1145 filename, linenum);
1146 } else if (n != 1)
1147 fatal("%s line %d: Illegal MaxStartups spec.",
1148 filename, linenum);
1149 else
1150 options->max_startups = options->max_startups_begin;
1151 break;
1153 case sMaxAuthTries:
1154 intptr = &options->max_authtries;
1155 goto parse_int;
1157 case sBanner:
1158 charptr = &options->banner;
1159 goto parse_filename;
1162 * These options can contain %X options expanded at
1163 * connect time, so that you can specify paths like:
1165 * AuthorizedKeysFile /etc/ssh_keys/%u
1167 case sAuthorizedKeysFile:
1168 case sAuthorizedKeysFile2:
1169 charptr = (opcode == sAuthorizedKeysFile) ?
1170 &options->authorized_keys_file :
1171 &options->authorized_keys_file2;
1172 goto parse_filename;
1174 case sClientAliveInterval:
1175 intptr = &options->client_alive_interval;
1176 goto parse_time;
1178 case sClientAliveCountMax:
1179 intptr = &options->client_alive_count_max;
1180 goto parse_int;
1182 case sAcceptEnv:
1183 while ((arg = strdelim(&cp)) && *arg != '\0') {
1184 if (strchr(arg, '=') != NULL)
1185 fatal("%s line %d: Invalid environment name.",
1186 filename, linenum);
1187 if (options->num_accept_env >= MAX_ACCEPT_ENV)
1188 fatal("%s line %d: too many allow env.",
1189 filename, linenum);
1190 if (!*activep)
1191 break;
1192 options->accept_env[options->num_accept_env++] =
1193 xstrdup(arg);
1195 break;
1197 case sPermitTunnel:
1198 intptr = &options->permit_tun;
1199 arg = strdelim(&cp);
1200 if (!arg || *arg == '\0')
1201 fatal("%s line %d: Missing yes/point-to-point/"
1202 "ethernet/no argument.", filename, linenum);
1203 value = 0; /* silence compiler */
1204 if (strcasecmp(arg, "ethernet") == 0)
1205 value = SSH_TUNMODE_ETHERNET;
1206 else if (strcasecmp(arg, "point-to-point") == 0)
1207 value = SSH_TUNMODE_POINTOPOINT;
1208 else if (strcasecmp(arg, "yes") == 0)
1209 value = SSH_TUNMODE_YES;
1210 else if (strcasecmp(arg, "no") == 0)
1211 value = SSH_TUNMODE_NO;
1212 else
1213 fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1214 "no argument: %s", filename, linenum, arg);
1215 if (*intptr == -1)
1216 *intptr = value;
1217 break;
1219 case sMatch:
1220 if (cmdline)
1221 fatal("Match directive not supported as a command-line "
1222 "option");
1223 value = match_cfg_line(&cp, linenum, user, host, address);
1224 if (value < 0)
1225 fatal("%s line %d: Bad Match condition", filename,
1226 linenum);
1227 *activep = value;
1228 break;
1230 case sPermitOpen:
1231 arg = strdelim(&cp);
1232 if (!arg || *arg == '\0')
1233 fatal("%s line %d: missing PermitOpen specification",
1234 filename, linenum);
1235 n = options->num_permitted_opens; /* modified later */
1236 if (strcmp(arg, "any") == 0) {
1237 if (*activep && n == -1) {
1238 channel_clear_adm_permitted_opens();
1239 options->num_permitted_opens = 0;
1241 break;
1243 if (*activep && n == -1)
1244 channel_clear_adm_permitted_opens();
1245 for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1246 p = hpdelim(&arg);
1247 if (p == NULL)
1248 fatal("%s line %d: missing host in PermitOpen",
1249 filename, linenum);
1250 p = cleanhostname(p);
1251 if (arg == NULL || (port = a2port(arg)) == 0)
1252 fatal("%s line %d: bad port number in "
1253 "PermitOpen", filename, linenum);
1254 if (*activep && n == -1)
1255 options->num_permitted_opens =
1256 channel_add_adm_permitted_opens(p, port);
1258 break;
1260 case sForceCommand:
1261 if (cp == NULL)
1262 fatal("%.200s line %d: Missing argument.", filename,
1263 linenum);
1264 len = strspn(cp, WHITESPACE);
1265 if (*activep && options->adm_forced_command == NULL)
1266 options->adm_forced_command = xstrdup(cp + len);
1267 return 0;
1269 case sChrootDirectory:
1270 charptr = &options->chroot_directory;
1272 arg = strdelim(&cp);
1273 if (!arg || *arg == '\0')
1274 fatal("%s line %d: missing file name.",
1275 filename, linenum);
1276 if (*activep && *charptr == NULL)
1277 *charptr = xstrdup(arg);
1278 break;
1280 case sVersionAddendum:
1281 ssh_version_set_addendum(strtok(cp, "\n"));
1282 do {
1283 arg = strdelim(&cp);
1284 } while (arg != NULL && *arg != '\0');
1285 break;
1287 case sDeprecated:
1288 logit("%s line %d: Deprecated option %s",
1289 filename, linenum, arg);
1290 while (arg)
1291 arg = strdelim(&cp);
1292 break;
1294 case sUnsupported:
1295 logit("%s line %d: Unsupported option %s",
1296 filename, linenum, arg);
1297 while (arg)
1298 arg = strdelim(&cp);
1299 break;
1301 default:
1302 fatal("%s line %d: Missing handler for opcode %s (%d)",
1303 filename, linenum, arg, opcode);
1305 if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
1306 fatal("%s line %d: garbage at end of line; \"%.200s\".",
1307 filename, linenum, arg);
1308 return 0;
1311 /* Reads the server configuration file. */
1313 void
1314 load_server_config(const char *filename, Buffer *conf)
1316 char line[1024], *cp;
1317 FILE *f;
1319 debug2("%s: filename %s", __func__, filename);
1320 if ((f = fopen(filename, "r")) == NULL) {
1321 perror(filename);
1322 exit(1);
1324 buffer_clear(conf);
1325 while (fgets(line, sizeof(line), f)) {
1327 * Trim out comments and strip whitespace
1328 * NB - preserve newlines, they are needed to reproduce
1329 * line numbers later for error messages
1331 if ((cp = strchr(line, '#')) != NULL)
1332 memcpy(cp, "\n", 2);
1333 cp = line + strspn(line, " \t\r");
1335 buffer_append(conf, cp, strlen(cp));
1337 buffer_append(conf, "\0", 1);
1338 fclose(f);
1339 debug2("%s: done config len = %d", __func__, buffer_len(conf));
1342 void
1343 parse_server_match_config(ServerOptions *options, const char *user,
1344 const char *host, const char *address)
1346 ServerOptions mo;
1348 initialize_server_options(&mo);
1349 parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
1350 copy_set_server_options(options, &mo, 0);
1353 /* Helper macros */
1354 #define M_CP_INTOPT(n) do {\
1355 if (src->n != -1) \
1356 dst->n = src->n; \
1357 } while (0)
1358 #define M_CP_STROPT(n) do {\
1359 if (src->n != NULL) { \
1360 if (dst->n != NULL) \
1361 xfree(dst->n); \
1362 dst->n = src->n; \
1364 } while(0)
1367 * Copy any supported values that are set.
1369 * If the preauth flag is set, we do not bother copying the the string or
1370 * array values that are not used pre-authentication, because any that we
1371 * do use must be explictly sent in mm_getpwnamallow().
1373 void
1374 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1376 M_CP_INTOPT(password_authentication);
1377 M_CP_INTOPT(gss_authentication);
1378 M_CP_INTOPT(rsa_authentication);
1379 M_CP_INTOPT(pubkey_authentication);
1380 M_CP_INTOPT(kerberos_authentication);
1381 M_CP_INTOPT(hostbased_authentication);
1382 M_CP_INTOPT(kbd_interactive_authentication);
1383 M_CP_INTOPT(permit_root_login);
1385 M_CP_INTOPT(allow_tcp_forwarding);
1386 M_CP_INTOPT(gateway_ports);
1387 M_CP_INTOPT(x11_display_offset);
1388 M_CP_INTOPT(x11_forwarding);
1389 M_CP_INTOPT(x11_use_localhost);
1391 M_CP_STROPT(banner);
1392 if (preauth)
1393 return;
1394 M_CP_STROPT(adm_forced_command);
1395 M_CP_STROPT(chroot_directory);
1398 #undef M_CP_INTOPT
1399 #undef M_CP_STROPT
1401 void
1402 parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1403 const char *user, const char *host, const char *address)
1405 int active, linenum, bad_options = 0;
1406 char *cp, *obuf, *cbuf;
1408 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1410 obuf = cbuf = xstrdup(buffer_ptr(conf));
1411 active = user ? 0 : 1;
1412 linenum = 1;
1413 while ((cp = strsep(&cbuf, "\n")) != NULL) {
1414 if (process_server_config_line(options, cp, filename,
1415 linenum++, &active, user, host, address) != 0)
1416 bad_options++;
1418 xfree(obuf);
1419 if (bad_options > 0)
1420 fatal("%s: terminating, %d bad configuration options",
1421 filename, bad_options);