]> andersk Git - gssapi-openssh.git/blame - openssh/servconf.c
http://www.psc.edu/networking/projects/hpn-ssh/openssh-5.1p1-hpn13v5.diff.gz committe...
[gssapi-openssh.git] / openssh / servconf.c
CommitLineData
22616013 1/* $OpenBSD: servconf.c,v 1.186 2008/07/04 03:44:59 djm Exp $ */
3c0ef626 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"
3c0ef626 14
9108f8d9 15#include <sys/types.h>
16#include <sys/socket.h>
17
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>
22616013 26#include <errno.h>
9108f8d9 27
22616013 28#include "openbsd-compat/sys-queue.h"
9108f8d9 29#include "xmalloc.h"
3c0ef626 30#include "ssh.h"
31#include "log.h"
9108f8d9 32#include "buffer.h"
3c0ef626 33#include "servconf.h"
3c0ef626 34#include "compat.h"
35#include "pathnames.h"
3c0ef626 36#include "misc.h"
37#include "cipher.h"
9108f8d9 38#include "key.h"
3c0ef626 39#include "kex.h"
40#include "mac.h"
9108f8d9 41#include "match.h"
42#include "channels.h"
43#include "groupaccess.h"
3c0ef626 44
45static void add_listen_addr(ServerOptions *, char *, u_short);
46static void add_one_listen_addr(ServerOptions *, char *, u_short);
47
700318f3 48/* Use of privilege separation or not */
49extern int use_privsep;
9108f8d9 50extern Buffer cfg;
3c0ef626 51
52/* Initializes the server options to their default values. */
53
54void
55initialize_server_options(ServerOptions *options)
56{
57 memset(options, 0, sizeof(*options));
58
59 /* Portable-specific options */
0fff78ff 60 options->use_pam = -1;
3c0ef626 61
62 /* Standard Options */
63 options->num_ports = 0;
64 options->ports_from_cmdline = 0;
65 options->listen_addrs = NULL;
996d5e62 66 options->address_family = -1;
3c0ef626 67 options->num_host_key_files = 0;
68 options->pid_file = NULL;
69 options->server_key_bits = -1;
70 options->login_grace_time = -1;
71 options->key_regeneration_time = -1;
72 options->permit_root_login = PERMIT_NOT_SET;
73 options->ignore_rhosts = -1;
74 options->ignore_user_known_hosts = -1;
75 options->print_motd = -1;
76 options->print_lastlog = -1;
77 options->x11_forwarding = -1;
78 options->x11_display_offset = -1;
e9a17296 79 options->x11_use_localhost = -1;
3c0ef626 80 options->xauth_location = NULL;
81 options->strict_modes = -1;
cdd66111 82 options->tcp_keep_alive = -1;
e9a17296 83 options->log_facility = SYSLOG_FACILITY_NOT_SET;
84 options->log_level = SYSLOG_LEVEL_NOT_SET;
3c0ef626 85 options->rhosts_rsa_authentication = -1;
86 options->hostbased_authentication = -1;
87 options->hostbased_uses_name_from_packet_only = -1;
88 options->rsa_authentication = -1;
89 options->pubkey_authentication = -1;
3c0ef626 90 options->kerberos_authentication = -1;
91 options->kerberos_or_local_passwd = -1;
92 options->kerberos_ticket_cleanup = -1;
cdd66111 93 options->kerberos_get_afs_token = -1;
0fff78ff 94 options->gss_authentication=-1;
95 options->gss_cleanup_creds = -1;
3c0ef626 96 options->password_authentication = -1;
97 options->kbd_interactive_authentication = -1;
98 options->challenge_response_authentication = -1;
99 options->permit_empty_passwd = -1;
41b2f314 100 options->permit_user_env = -1;
3c0ef626 101 options->use_login = -1;
f5799ae1 102 options->compression = -1;
3c0ef626 103 options->allow_tcp_forwarding = -1;
22616013 104 options->allow_agent_forwarding = -1;
3c0ef626 105 options->num_allow_users = 0;
106 options->num_deny_users = 0;
107 options->num_allow_groups = 0;
108 options->num_deny_groups = 0;
109 options->ciphers = NULL;
110 options->macs = NULL;
111 options->protocol = SSH_PROTO_UNKNOWN;
112 options->gateway_ports = -1;
113 options->num_subsystems = 0;
114 options->max_startups_begin = -1;
115 options->max_startups_rate = -1;
116 options->max_startups = -1;
c9f39d2c 117 options->max_authtries = -1;
22616013 118 options->max_sessions = -1;
3c0ef626 119 options->banner = NULL;
0fff78ff 120 options->use_dns = -1;
3c0ef626 121 options->client_alive_interval = -1;
122 options->client_alive_count_max = -1;
123 options->authorized_keys_file = NULL;
124 options->authorized_keys_file2 = NULL;
c9f39d2c 125 options->num_accept_env = 0;
2c06c99b 126 options->permit_tun = -1;
9108f8d9 127 options->num_permitted_opens = -1;
128 options->adm_forced_command = NULL;
47686178 129 options->chroot_directory = NULL;
c015d727 130 options->none_enabled = -1;
131 options->tcp_rcv_buf_poll = -1;
132 options->hpn_disabled = -1;
133 options->hpn_buffer_size = -1;
3c0ef626 134}
135
136void
137fill_default_server_options(ServerOptions *options)
138{
c015d727 139 /* needed for hpn socket tests */
140 int sock;
141 int socksize;
142 int socksizelen = sizeof(int);
143
3c0ef626 144 /* Portable-specific options */
0fff78ff 145 if (options->use_pam == -1)
acc3d05e 146 options->use_pam = 0;
3c0ef626 147
148 /* Standard Options */
149 if (options->protocol == SSH_PROTO_UNKNOWN)
150 options->protocol = SSH_PROTO_1|SSH_PROTO_2;
151 if (options->num_host_key_files == 0) {
152 /* fill default hostkeys for protocols */
153 if (options->protocol & SSH_PROTO_1)
e9a17296 154 options->host_key_files[options->num_host_key_files++] =
155 _PATH_HOST_KEY_FILE;
156 if (options->protocol & SSH_PROTO_2) {
157 options->host_key_files[options->num_host_key_files++] =
158 _PATH_HOST_RSA_KEY_FILE;
159 options->host_key_files[options->num_host_key_files++] =
160 _PATH_HOST_DSA_KEY_FILE;
161 }
3c0ef626 162 }
163 if (options->num_ports == 0)
164 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
165 if (options->listen_addrs == NULL)
166 add_listen_addr(options, NULL, 0);
167 if (options->pid_file == NULL)
168 options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
169 if (options->server_key_bits == -1)
22616013 170 options->server_key_bits = 1024;
3c0ef626 171 if (options->login_grace_time == -1)
41b2f314 172 options->login_grace_time = 120;
3c0ef626 173 if (options->key_regeneration_time == -1)
174 options->key_regeneration_time = 3600;
175 if (options->permit_root_login == PERMIT_NOT_SET)
176 options->permit_root_login = PERMIT_YES;
177 if (options->ignore_rhosts == -1)
178 options->ignore_rhosts = 1;
179 if (options->ignore_user_known_hosts == -1)
180 options->ignore_user_known_hosts = 0;
181 if (options->print_motd == -1)
182 options->print_motd = 1;
183 if (options->print_lastlog == -1)
184 options->print_lastlog = 1;
185 if (options->x11_forwarding == -1)
186 options->x11_forwarding = 0;
187 if (options->x11_display_offset == -1)
188 options->x11_display_offset = 10;
e9a17296 189 if (options->x11_use_localhost == -1)
190 options->x11_use_localhost = 1;
3c0ef626 191 if (options->xauth_location == NULL)
192 options->xauth_location = _PATH_XAUTH;
3c0ef626 193 if (options->strict_modes == -1)
194 options->strict_modes = 1;
cdd66111 195 if (options->tcp_keep_alive == -1)
196 options->tcp_keep_alive = 1;
e9a17296 197 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
3c0ef626 198 options->log_facility = SYSLOG_FACILITY_AUTH;
e9a17296 199 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
3c0ef626 200 options->log_level = SYSLOG_LEVEL_INFO;
3c0ef626 201 if (options->rhosts_rsa_authentication == -1)
202 options->rhosts_rsa_authentication = 0;
203 if (options->hostbased_authentication == -1)
204 options->hostbased_authentication = 0;
205 if (options->hostbased_uses_name_from_packet_only == -1)
206 options->hostbased_uses_name_from_packet_only = 0;
207 if (options->rsa_authentication == -1)
208 options->rsa_authentication = 1;
209 if (options->pubkey_authentication == -1)
210 options->pubkey_authentication = 1;
3c0ef626 211 if (options->kerberos_authentication == -1)
700318f3 212 options->kerberos_authentication = 0;
3c0ef626 213 if (options->kerberos_or_local_passwd == -1)
214 options->kerberos_or_local_passwd = 1;
215 if (options->kerberos_ticket_cleanup == -1)
216 options->kerberos_ticket_cleanup = 1;
cdd66111 217 if (options->kerberos_get_afs_token == -1)
218 options->kerberos_get_afs_token = 0;
0fff78ff 219 if (options->gss_authentication == -1)
220 options->gss_authentication = 0;
221 if (options->gss_cleanup_creds == -1)
222 options->gss_cleanup_creds = 1;
3c0ef626 223 if (options->password_authentication == -1)
224 options->password_authentication = 1;
225 if (options->kbd_interactive_authentication == -1)
226 options->kbd_interactive_authentication = 0;
227 if (options->challenge_response_authentication == -1)
228 options->challenge_response_authentication = 1;
229 if (options->permit_empty_passwd == -1)
230 options->permit_empty_passwd = 0;
41b2f314 231 if (options->permit_user_env == -1)
232 options->permit_user_env = 0;
3c0ef626 233 if (options->use_login == -1)
234 options->use_login = 0;
f5799ae1 235 if (options->compression == -1)
665a873d 236 options->compression = COMP_DELAYED;
3c0ef626 237 if (options->allow_tcp_forwarding == -1)
238 options->allow_tcp_forwarding = 1;
22616013 239 if (options->allow_agent_forwarding == -1)
240 options->allow_agent_forwarding = 1;
3c0ef626 241 if (options->gateway_ports == -1)
242 options->gateway_ports = 0;
243 if (options->max_startups == -1)
244 options->max_startups = 10;
245 if (options->max_startups_rate == -1)
246 options->max_startups_rate = 100; /* 100% */
247 if (options->max_startups_begin == -1)
248 options->max_startups_begin = options->max_startups;
c9f39d2c 249 if (options->max_authtries == -1)
250 options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
22616013 251 if (options->max_sessions == -1)
252 options->max_sessions = DEFAULT_SESSIONS_MAX;
0fff78ff 253 if (options->use_dns == -1)
254 options->use_dns = 1;
3c0ef626 255 if (options->client_alive_interval == -1)
e9a17296 256 options->client_alive_interval = 0;
3c0ef626 257 if (options->client_alive_count_max == -1)
258 options->client_alive_count_max = 3;
259 if (options->authorized_keys_file2 == NULL) {
260 /* authorized_keys_file2 falls back to authorized_keys_file */
261 if (options->authorized_keys_file != NULL)
262 options->authorized_keys_file2 = options->authorized_keys_file;
263 else
264 options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
265 }
266 if (options->authorized_keys_file == NULL)
267 options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
2c06c99b 268 if (options->permit_tun == -1)
269 options->permit_tun = SSH_TUNMODE_NO;
700318f3 270
c015d727 271 if (options->hpn_disabled == -1)
272 options->hpn_disabled = 0;
273
274 if (options->hpn_buffer_size == -1) {
275 /* option not explicitly set. Now we have to figure out */
276 /* what value to use */
277 if (options->hpn_disabled == 1) {
278 options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
279 } else {
280 /* get the current RCV size and set it to that */
281 /*create a socket but don't connect it */
282 /* we use that the get the rcv socket size */
283 sock = socket(AF_INET, SOCK_STREAM, 0);
284 getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
285 &socksize, &socksizelen);
286 close(sock);
287 options->hpn_buffer_size = socksize;
288 debug ("HPN Buffer Size: %d", options->hpn_buffer_size);
289
290 }
291 } else {
292 /* we have to do this incase the user sets both values in a contradictory */
293 /* manner. hpn_disabled overrrides hpn_buffer_size*/
294 if (options->hpn_disabled <= 0) {
295 if (options->hpn_buffer_size == 0)
296 options->hpn_buffer_size = 1;
297 /* limit the maximum buffer to 64MB */
298 if (options->hpn_buffer_size > 64*1024) {
299 options->hpn_buffer_size = 64*1024*1024;
300 } else {
301 options->hpn_buffer_size *= 1024;
302 }
303 } else
304 options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT;
305 }
306
f5799ae1 307 /* Turn privilege separation on by default */
700318f3 308 if (use_privsep == -1)
f5799ae1 309 use_privsep = 1;
310
41b2f314 311#ifndef HAVE_MMAP
f5799ae1 312 if (use_privsep && options->compression == 1) {
313 error("This platform does not support both privilege "
314 "separation and compression");
315 error("Compression disabled");
316 options->compression = 0;
317 }
318#endif
319
3c0ef626 320}
321
322/* Keyword tokens. */
323typedef enum {
324 sBadOption, /* == unknown option */
325 /* Portable-specific options */
0fff78ff 326 sUsePAM,
3c0ef626 327 /* Standard Options */
328 sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
329 sPermitRootLogin, sLogFacility, sLogLevel,
0fff78ff 330 sRhostsRSAAuthentication, sRSAAuthentication,
3c0ef626 331 sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
cdd66111 332 sKerberosGetAFSToken,
0fff78ff 333 sKerberosTgtPassing, sChallengeResponseAuthentication,
996d5e62 334 sPasswordAuthentication, sKbdInteractiveAuthentication,
335 sListenAddress, sAddressFamily,
3c0ef626 336 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
e9a17296 337 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
cdd66111 338 sStrictModes, sEmptyPasswd, sTCPKeepAlive,
41b2f314 339 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
3c0ef626 340 sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
341 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
c9f39d2c 342 sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
22616013 343 sMaxStartups, sMaxAuthTries, sMaxSessions,
0fff78ff 344 sBanner, sUseDNS, sHostbasedAuthentication,
e9a17296 345 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
3c0ef626 346 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
2c06c99b 347 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
47686178 348 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
22616013 349 sUsePrivilegeSeparation, sAllowAgentForwarding,
c015d727 350 sNoneEnabled, sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize,
0fff78ff 351 sDeprecated, sUnsupported
3c0ef626 352} ServerOpCodes;
353
9108f8d9 354#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
355#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
356#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
357
3c0ef626 358/* Textual representation of the tokens. */
359static struct {
360 const char *name;
361 ServerOpCodes opcode;
9108f8d9 362 u_int flags;
3c0ef626 363} keywords[] = {
364 /* Portable-specific options */
0fff78ff 365#ifdef USE_PAM
9108f8d9 366 { "usepam", sUsePAM, SSHCFG_GLOBAL },
0fff78ff 367#else
9108f8d9 368 { "usepam", sUnsupported, SSHCFG_GLOBAL },
0fff78ff 369#endif
9108f8d9 370 { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
3c0ef626 371 /* Standard Options */
9108f8d9 372 { "port", sPort, SSHCFG_GLOBAL },
373 { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
374 { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
375 { "pidfile", sPidFile, SSHCFG_GLOBAL },
376 { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
377 { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
378 { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
47686178 379 { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
9108f8d9 380 { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
381 { "loglevel", sLogLevel, SSHCFG_GLOBAL },
382 { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
799ae497 383 { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
384 { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
9108f8d9 385 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
799ae497 386 { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
387 { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
9108f8d9 388 { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
0fff78ff 389#ifdef KRB5
799ae497 390 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
9108f8d9 391 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
392 { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
cdd66111 393#ifdef USE_AFS
9108f8d9 394 { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
cdd66111 395#else
9108f8d9 396 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
cdd66111 397#endif
0fff78ff 398#else
799ae497 399 { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
9108f8d9 400 { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
401 { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
402 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
3c0ef626 403#endif
9108f8d9 404 { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
405 { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
0fff78ff 406#ifdef GSSAPI
799ae497 407 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
9108f8d9 408 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
0fff78ff 409#else
799ae497 410 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
9108f8d9 411 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
3c0ef626 412#endif
799ae497 413 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
414 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
9108f8d9 415 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
416 { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
417 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
418 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
419 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
420 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
421 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
422 { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
423 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
424 { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
425 { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
426 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
427 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
428 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
429 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
430 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
431 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
432 { "compression", sCompression, SSHCFG_GLOBAL },
433 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
434 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
435 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
22616013 436 { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
9108f8d9 437 { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
438 { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
439 { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
440 { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
441 { "ciphers", sCiphers, SSHCFG_GLOBAL },
442 { "macs", sMacs, SSHCFG_GLOBAL },
443 { "protocol", sProtocol, SSHCFG_GLOBAL },
444 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
445 { "subsystem", sSubsystem, SSHCFG_GLOBAL },
446 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
22616013 447 { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
448 { "maxsessions", sMaxSessions, SSHCFG_ALL },
799ae497 449 { "banner", sBanner, SSHCFG_ALL },
9108f8d9 450 { "usedns", sUseDNS, SSHCFG_GLOBAL },
451 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
452 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
453 { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
454 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
455 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
456 { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
457 { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
458 { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
459 { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
460 { "match", sMatch, SSHCFG_ALL },
461 { "permitopen", sPermitOpen, SSHCFG_ALL },
462 { "forcecommand", sForceCommand, SSHCFG_ALL },
47686178 463 { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
c015d727 464 { "noneenabled", sNoneEnabled },
465 { "hpndisabled", sHPNDisabled },
466 { "hpnbuffersize", sHPNBufferSize },
467 { "tcprcvbufpoll", sTcpRcvBufPoll },
9108f8d9 468 { NULL, sBadOption, 0 }
3c0ef626 469};
470
22616013 471static struct {
472 int val;
473 char *text;
474} tunmode_desc[] = {
475 { SSH_TUNMODE_NO, "no" },
476 { SSH_TUNMODE_POINTOPOINT, "point-to-point" },
477 { SSH_TUNMODE_ETHERNET, "ethernet" },
478 { SSH_TUNMODE_YES, "yes" },
479 { -1, NULL }
480};
481
3c0ef626 482/*
483 * Returns the number of the token pointed to by cp or sBadOption.
484 */
485
486static ServerOpCodes
487parse_token(const char *cp, const char *filename,
9108f8d9 488 int linenum, u_int *flags)
3c0ef626 489{
490 u_int i;
491
492 for (i = 0; keywords[i].name; i++)
9108f8d9 493 if (strcasecmp(cp, keywords[i].name) == 0) {
c015d727 494 debug ("Config token is %s", keywords[i].name);
9108f8d9 495 *flags = keywords[i].flags;
3c0ef626 496 return keywords[i].opcode;
9108f8d9 497 }
3c0ef626 498
499 error("%s: line %d: Bad configuration option: %s",
500 filename, linenum, cp);
501 return sBadOption;
502}
503
504static void
505add_listen_addr(ServerOptions *options, char *addr, u_short port)
506{
665a873d 507 u_int i;
3c0ef626 508
509 if (options->num_ports == 0)
510 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
996d5e62 511 if (options->address_family == -1)
512 options->address_family = AF_UNSPEC;
3c0ef626 513 if (port == 0)
514 for (i = 0; i < options->num_ports; i++)
515 add_one_listen_addr(options, addr, options->ports[i]);
516 else
517 add_one_listen_addr(options, addr, port);
518}
519
520static void
521add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
522{
523 struct addrinfo hints, *ai, *aitop;
524 char strport[NI_MAXSERV];
525 int gaierr;
526
527 memset(&hints, 0, sizeof(hints));
996d5e62 528 hints.ai_family = options->address_family;
3c0ef626 529 hints.ai_socktype = SOCK_STREAM;
530 hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
680cee3b 531 snprintf(strport, sizeof strport, "%u", port);
3c0ef626 532 if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
533 fatal("bad addr or host: %s (%s)",
534 addr ? addr : "<NULL>",
47686178 535 ssh_gai_strerror(gaierr));
3c0ef626 536 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
537 ;
538 ai->ai_next = options->listen_addrs;
539 options->listen_addrs = aitop;
540}
541
9108f8d9 542/*
543 * The strategy for the Match blocks is that the config file is parsed twice.
544 *
545 * The first time is at startup. activep is initialized to 1 and the
546 * directives in the global context are processed and acted on. Hitting a
547 * Match directive unsets activep and the directives inside the block are
548 * checked for syntax only.
549 *
550 * The second time is after a connection has been established but before
551 * authentication. activep is initialized to 2 and global config directives
552 * are ignored since they have already been processed. If the criteria in a
553 * Match block is met, activep is set and the subsequent directives
554 * processed and actioned until EOF or another Match block unsets it. Any
555 * options set are copied into the main server config.
556 *
557 * Potential additions/improvements:
558 * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
559 *
560 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
561 * Match Address 192.168.0.*
562 * Tag trusted
563 * Match Group wheel
564 * Tag trusted
565 * Match Tag trusted
566 * AllowTcpForwarding yes
567 * GatewayPorts clientspecified
568 * [...]
569 *
570 * - Add a PermittedChannelRequests directive
571 * Match Group shell
572 * PermittedChannelRequests session,forwarded-tcpip
573 */
574
575static int
576match_cfg_line_group(const char *grps, int line, const char *user)
577{
578 int result = 0;
9108f8d9 579 struct passwd *pw;
580
9108f8d9 581 if (user == NULL)
582 goto out;
583
584 if ((pw = getpwnam(user)) == NULL) {
585 debug("Can't match group at line %d because user %.100s does "
586 "not exist", line, user);
587 } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
588 debug("Can't Match group because user %.100s not in any group "
589 "at line %d", user, line);
22616013 590 } else if (ga_match_pattern_list(grps) != 1) {
591 debug("user %.100s does not match group list %.100s at line %d",
592 user, grps, line);
9108f8d9 593 } else {
22616013 594 debug("user %.100s matched group list %.100s at line %d", user,
595 grps, line);
9108f8d9 596 result = 1;
597 }
598out:
599 ga_free();
9108f8d9 600 return result;
601}
602
603static int
604match_cfg_line(char **condition, int line, const char *user, const char *host,
605 const char *address)
606{
607 int result = 1;
608 char *arg, *attrib, *cp = *condition;
609 size_t len;
610
611 if (user == NULL)
612 debug3("checking syntax for 'Match %s'", cp);
613 else
614 debug3("checking match for '%s' user %s host %s addr %s", cp,
615 user ? user : "(null)", host ? host : "(null)",
616 address ? address : "(null)");
617
618 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
619 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
620 error("Missing Match criteria for %s", attrib);
621 return -1;
622 }
623 len = strlen(arg);
624 if (strcasecmp(attrib, "user") == 0) {
625 if (!user) {
626 result = 0;
627 continue;
628 }
629 if (match_pattern_list(user, arg, len, 0) != 1)
630 result = 0;
631 else
632 debug("user %.100s matched 'User %.100s' at "
633 "line %d", user, arg, line);
634 } else if (strcasecmp(attrib, "group") == 0) {
635 switch (match_cfg_line_group(arg, line, user)) {
636 case -1:
637 return -1;
638 case 0:
639 result = 0;
640 }
641 } else if (strcasecmp(attrib, "host") == 0) {
642 if (!host) {
643 result = 0;
644 continue;
645 }
646 if (match_hostname(host, arg, len) != 1)
647 result = 0;
648 else
649 debug("connection from %.100s matched 'Host "
650 "%.100s' at line %d", host, arg, line);
651 } else if (strcasecmp(attrib, "address") == 0) {
22616013 652 switch (addr_match_list(address, arg)) {
653 case 1:
9108f8d9 654 debug("connection from %.100s matched 'Address "
655 "%.100s' at line %d", address, arg, line);
22616013 656 break;
657 case 0:
658 case -1:
659 result = 0;
660 break;
661 case -2:
662 return -1;
663 }
9108f8d9 664 } else {
665 error("Unsupported Match attribute %s", attrib);
666 return -1;
667 }
668 }
669 if (user != NULL)
670 debug3("match %sfound", result ? "" : "not ");
671 *condition = cp;
672 return result;
673}
674
675#define WHITESPACE " \t\r\n"
676
e9a17296 677int
678process_server_config_line(ServerOptions *options, char *line,
9108f8d9 679 const char *filename, int linenum, int *activep, const char *user,
680 const char *host, const char *address)
3c0ef626 681{
3c0ef626 682 char *cp, **charptr, *arg, *p;
9108f8d9 683 int cmdline = 0, *intptr, value, n;
47686178 684 SyslogFacility *log_facility_ptr;
685 LogLevel *log_level_ptr;
3c0ef626 686 ServerOpCodes opcode;
996d5e62 687 u_short port;
9108f8d9 688 u_int i, flags = 0;
689 size_t len;
3c0ef626 690
e9a17296 691 cp = line;
9108f8d9 692 if ((arg = strdelim(&cp)) == NULL)
693 return 0;
e9a17296 694 /* Ignore leading whitespace */
695 if (*arg == '\0')
3c0ef626 696 arg = strdelim(&cp);
e9a17296 697 if (!arg || !*arg || *arg == '#')
698 return 0;
699 intptr = NULL;
700 charptr = NULL;
9108f8d9 701 opcode = parse_token(arg, filename, linenum, &flags);
702
703 if (activep == NULL) { /* We are processing a command line directive */
704 cmdline = 1;
705 activep = &cmdline;
706 }
707 if (*activep && opcode != sMatch)
708 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
709 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
710 if (user == NULL) {
711 fatal("%s line %d: Directive '%s' is not allowed "
712 "within a Match block", filename, linenum, arg);
713 } else { /* this is a directive we have already processed */
714 while (arg)
715 arg = strdelim(&cp);
716 return 0;
717 }
718 }
719
e9a17296 720 switch (opcode) {
721 /* Portable-specific options */
0fff78ff 722 case sUsePAM:
723 intptr = &options->use_pam;
e9a17296 724 goto parse_flag;
3c0ef626 725
e9a17296 726 /* Standard Options */
727 case sBadOption:
728 return -1;
729 case sPort:
730 /* ignore ports from configfile if cmdline specifies ports */
731 if (options->ports_from_cmdline)
732 return 0;
733 if (options->listen_addrs != NULL)
734 fatal("%s line %d: ports must be specified before "
735 "ListenAddress.", filename, linenum);
736 if (options->num_ports >= MAX_PORTS)
737 fatal("%s line %d: too many ports.",
738 filename, linenum);
739 arg = strdelim(&cp);
740 if (!arg || *arg == '\0')
741 fatal("%s line %d: missing port number.",
742 filename, linenum);
743 options->ports[options->num_ports++] = a2port(arg);
744 if (options->ports[options->num_ports-1] == 0)
745 fatal("%s line %d: Badly formatted port number.",
746 filename, linenum);
747 break;
748
749 case sServerKeyBits:
750 intptr = &options->server_key_bits;
22616013 751 parse_int:
e9a17296 752 arg = strdelim(&cp);
753 if (!arg || *arg == '\0')
754 fatal("%s line %d: missing integer value.",
755 filename, linenum);
756 value = atoi(arg);
9108f8d9 757 if (*activep && *intptr == -1)
e9a17296 758 *intptr = value;
759 break;
760
761 case sLoginGraceTime:
762 intptr = &options->login_grace_time;
22616013 763 parse_time:
e9a17296 764 arg = strdelim(&cp);
765 if (!arg || *arg == '\0')
766 fatal("%s line %d: missing time value.",
767 filename, linenum);
768 if ((value = convtime(arg)) == -1)
769 fatal("%s line %d: invalid time value.",
770 filename, linenum);
771 if (*intptr == -1)
772 *intptr = value;
773 break;
774
775 case sKeyRegenerationTime:
776 intptr = &options->key_regeneration_time;
777 goto parse_time;
778
779 case sListenAddress:
780 arg = strdelim(&cp);
996d5e62 781 if (arg == NULL || *arg == '\0')
782 fatal("%s line %d: missing address",
e9a17296 783 filename, linenum);
665a873d 784 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
785 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
786 && strchr(p+1, ':') != NULL) {
787 add_listen_addr(options, arg, 0);
788 break;
789 }
996d5e62 790 p = hpdelim(&arg);
791 if (p == NULL)
792 fatal("%s line %d: bad address:port usage",
e9a17296 793 filename, linenum);
996d5e62 794 p = cleanhostname(p);
795 if (arg == NULL)
796 port = 0;
797 else if ((port = a2port(arg)) == 0)
798 fatal("%s line %d: bad port number", filename, linenum);
799
800 add_listen_addr(options, p, port);
801
802 break;
803
804 case sAddressFamily:
805 arg = strdelim(&cp);
665a873d 806 if (!arg || *arg == '\0')
807 fatal("%s line %d: missing address family.",
808 filename, linenum);
996d5e62 809 intptr = &options->address_family;
810 if (options->listen_addrs != NULL)
811 fatal("%s line %d: address family must be specified before "
812 "ListenAddress.", filename, linenum);
813 if (strcasecmp(arg, "inet") == 0)
814 value = AF_INET;
815 else if (strcasecmp(arg, "inet6") == 0)
816 value = AF_INET6;
817 else if (strcasecmp(arg, "any") == 0)
818 value = AF_UNSPEC;
819 else
820 fatal("%s line %d: unsupported address family \"%s\".",
821 filename, linenum, arg);
822 if (*intptr == -1)
823 *intptr = value;
e9a17296 824 break;
825
826 case sHostKeyFile:
827 intptr = &options->num_host_key_files;
828 if (*intptr >= MAX_HOSTKEYS)
829 fatal("%s line %d: too many host keys specified (max %d).",
830 filename, linenum, MAX_HOSTKEYS);
831 charptr = &options->host_key_files[*intptr];
22616013 832 parse_filename:
e9a17296 833 arg = strdelim(&cp);
834 if (!arg || *arg == '\0')
835 fatal("%s line %d: missing file name.",
836 filename, linenum);
9108f8d9 837 if (*activep && *charptr == NULL) {
e9a17296 838 *charptr = tilde_expand_filename(arg, getuid());
839 /* increase optional counter */
840 if (intptr != NULL)
841 *intptr = *intptr + 1;
842 }
843 break;
3c0ef626 844
e9a17296 845 case sPidFile:
846 charptr = &options->pid_file;
847 goto parse_filename;
3c0ef626 848
e9a17296 849 case sPermitRootLogin:
850 intptr = &options->permit_root_login;
851 arg = strdelim(&cp);
852 if (!arg || *arg == '\0')
853 fatal("%s line %d: missing yes/"
854 "without-password/forced-commands-only/no "
855 "argument.", filename, linenum);
856 value = 0; /* silence compiler */
857 if (strcmp(arg, "without-password") == 0)
858 value = PERMIT_NO_PASSWD;
859 else if (strcmp(arg, "forced-commands-only") == 0)
860 value = PERMIT_FORCED_ONLY;
861 else if (strcmp(arg, "yes") == 0)
862 value = PERMIT_YES;
863 else if (strcmp(arg, "no") == 0)
864 value = PERMIT_NO;
865 else
866 fatal("%s line %d: Bad yes/"
867 "without-password/forced-commands-only/no "
868 "argument: %s", filename, linenum, arg);
47686178 869 if (*activep && *intptr == -1)
e9a17296 870 *intptr = value;
871 break;
872
873 case sIgnoreRhosts:
874 intptr = &options->ignore_rhosts;
22616013 875 parse_flag:
e9a17296 876 arg = strdelim(&cp);
877 if (!arg || *arg == '\0')
878 fatal("%s line %d: missing yes/no argument.",
879 filename, linenum);
880 value = 0; /* silence compiler */
881 if (strcmp(arg, "yes") == 0)
882 value = 1;
883 else if (strcmp(arg, "no") == 0)
884 value = 0;
885 else
886 fatal("%s line %d: Bad yes/no argument: %s",
887 filename, linenum, arg);
9108f8d9 888 if (*activep && *intptr == -1)
e9a17296 889 *intptr = value;
890 break;
891
c015d727 892 case sNoneEnabled:
893 intptr = &options->none_enabled;
894 goto parse_flag;
895
896 case sTcpRcvBufPoll:
897 intptr = &options->tcp_rcv_buf_poll;
898 goto parse_flag;
899
900 case sHPNDisabled:
901 intptr = &options->hpn_disabled;
902 goto parse_flag;
903
904 case sHPNBufferSize:
905 intptr = &options->hpn_buffer_size;
906 goto parse_int;
907
e9a17296 908 case sIgnoreUserKnownHosts:
909 intptr = &options->ignore_user_known_hosts;
910 goto parse_flag;
911
e9a17296 912 case sRhostsRSAAuthentication:
913 intptr = &options->rhosts_rsa_authentication;
914 goto parse_flag;
915
916 case sHostbasedAuthentication:
917 intptr = &options->hostbased_authentication;
918 goto parse_flag;
919
920 case sHostbasedUsesNameFromPacketOnly:
921 intptr = &options->hostbased_uses_name_from_packet_only;
922 goto parse_flag;
923
924 case sRSAAuthentication:
925 intptr = &options->rsa_authentication;
926 goto parse_flag;
927
928 case sPubkeyAuthentication:
929 intptr = &options->pubkey_authentication;
930 goto parse_flag;
0fff78ff 931
e9a17296 932 case sKerberosAuthentication:
933 intptr = &options->kerberos_authentication;
934 goto parse_flag;
3c0ef626 935
e9a17296 936 case sKerberosOrLocalPasswd:
937 intptr = &options->kerberos_or_local_passwd;
938 goto parse_flag;
3c0ef626 939
e9a17296 940 case sKerberosTicketCleanup:
941 intptr = &options->kerberos_ticket_cleanup;
942 goto parse_flag;
0fff78ff 943
cdd66111 944 case sKerberosGetAFSToken:
945 intptr = &options->kerberos_get_afs_token;
946 goto parse_flag;
947
0fff78ff 948 case sGssAuthentication:
949 intptr = &options->gss_authentication;
e9a17296 950 goto parse_flag;
0fff78ff 951
952 case sGssCleanupCreds:
953 intptr = &options->gss_cleanup_creds;
e9a17296 954 goto parse_flag;
3c0ef626 955
e9a17296 956 case sPasswordAuthentication:
957 intptr = &options->password_authentication;
958 goto parse_flag;
3c0ef626 959
e9a17296 960 case sKbdInteractiveAuthentication:
961 intptr = &options->kbd_interactive_authentication;
962 goto parse_flag;
3c0ef626 963
e9a17296 964 case sChallengeResponseAuthentication:
965 intptr = &options->challenge_response_authentication;
966 goto parse_flag;
3c0ef626 967
e9a17296 968 case sPrintMotd:
969 intptr = &options->print_motd;
970 goto parse_flag;
3c0ef626 971
e9a17296 972 case sPrintLastLog:
973 intptr = &options->print_lastlog;
974 goto parse_flag;
3c0ef626 975
e9a17296 976 case sX11Forwarding:
977 intptr = &options->x11_forwarding;
978 goto parse_flag;
3c0ef626 979
e9a17296 980 case sX11DisplayOffset:
981 intptr = &options->x11_display_offset;
982 goto parse_int;
3c0ef626 983
e9a17296 984 case sX11UseLocalhost:
985 intptr = &options->x11_use_localhost;
986 goto parse_flag;
3c0ef626 987
e9a17296 988 case sXAuthLocation:
989 charptr = &options->xauth_location;
990 goto parse_filename;
3c0ef626 991
e9a17296 992 case sStrictModes:
993 intptr = &options->strict_modes;
994 goto parse_flag;
3c0ef626 995
cdd66111 996 case sTCPKeepAlive:
997 intptr = &options->tcp_keep_alive;
e9a17296 998 goto parse_flag;
3c0ef626 999
e9a17296 1000 case sEmptyPasswd:
1001 intptr = &options->permit_empty_passwd;
1002 goto parse_flag;
3c0ef626 1003
41b2f314 1004 case sPermitUserEnvironment:
1005 intptr = &options->permit_user_env;
1006 goto parse_flag;
1007
e9a17296 1008 case sUseLogin:
1009 intptr = &options->use_login;
1010 goto parse_flag;
3c0ef626 1011
f5799ae1 1012 case sCompression:
1013 intptr = &options->compression;
665a873d 1014 arg = strdelim(&cp);
1015 if (!arg || *arg == '\0')
1016 fatal("%s line %d: missing yes/no/delayed "
1017 "argument.", filename, linenum);
1018 value = 0; /* silence compiler */
1019 if (strcmp(arg, "delayed") == 0)
1020 value = COMP_DELAYED;
1021 else if (strcmp(arg, "yes") == 0)
1022 value = COMP_ZLIB;
1023 else if (strcmp(arg, "no") == 0)
1024 value = COMP_NONE;
1025 else
1026 fatal("%s line %d: Bad yes/no/delayed "
1027 "argument: %s", filename, linenum, arg);
1028 if (*intptr == -1)
1029 *intptr = value;
1030 break;
f5799ae1 1031
e9a17296 1032 case sGatewayPorts:
1033 intptr = &options->gateway_ports;
996d5e62 1034 arg = strdelim(&cp);
1035 if (!arg || *arg == '\0')
1036 fatal("%s line %d: missing yes/no/clientspecified "
1037 "argument.", filename, linenum);
1038 value = 0; /* silence compiler */
1039 if (strcmp(arg, "clientspecified") == 0)
1040 value = 2;
1041 else if (strcmp(arg, "yes") == 0)
1042 value = 1;
1043 else if (strcmp(arg, "no") == 0)
1044 value = 0;
1045 else
1046 fatal("%s line %d: Bad yes/no/clientspecified "
1047 "argument: %s", filename, linenum, arg);
799ae497 1048 if (*activep && *intptr == -1)
996d5e62 1049 *intptr = value;
1050 break;
3c0ef626 1051
0fff78ff 1052 case sUseDNS:
1053 intptr = &options->use_dns;
e9a17296 1054 goto parse_flag;
3c0ef626 1055
e9a17296 1056 case sLogFacility:
47686178 1057 log_facility_ptr = &options->log_facility;
e9a17296 1058 arg = strdelim(&cp);
1059 value = log_facility_number(arg);
1060 if (value == SYSLOG_FACILITY_NOT_SET)
1061 fatal("%.200s line %d: unsupported log facility '%s'",
1062 filename, linenum, arg ? arg : "<NONE>");
47686178 1063 if (*log_facility_ptr == -1)
1064 *log_facility_ptr = (SyslogFacility) value;
e9a17296 1065 break;
1066
1067 case sLogLevel:
47686178 1068 log_level_ptr = &options->log_level;
e9a17296 1069 arg = strdelim(&cp);
1070 value = log_level_number(arg);
1071 if (value == SYSLOG_LEVEL_NOT_SET)
1072 fatal("%.200s line %d: unsupported log level '%s'",
1073 filename, linenum, arg ? arg : "<NONE>");
47686178 1074 if (*log_level_ptr == -1)
1075 *log_level_ptr = (LogLevel) value;
e9a17296 1076 break;
1077
1078 case sAllowTcpForwarding:
1079 intptr = &options->allow_tcp_forwarding;
1080 goto parse_flag;
1081
22616013 1082 case sAllowAgentForwarding:
1083 intptr = &options->allow_agent_forwarding;
1084 goto parse_flag;
1085
700318f3 1086 case sUsePrivilegeSeparation:
1087 intptr = &use_privsep;
1088 goto parse_flag;
1089
e9a17296 1090 case sAllowUsers:
1091 while ((arg = strdelim(&cp)) && *arg != '\0') {
1092 if (options->num_allow_users >= MAX_ALLOW_USERS)
1093 fatal("%s line %d: too many allow users.",
1094 filename, linenum);
680cee3b 1095 options->allow_users[options->num_allow_users++] =
1096 xstrdup(arg);
e9a17296 1097 }
1098 break;
3c0ef626 1099
e9a17296 1100 case sDenyUsers:
1101 while ((arg = strdelim(&cp)) && *arg != '\0') {
1102 if (options->num_deny_users >= MAX_DENY_USERS)
9108f8d9 1103 fatal("%s line %d: too many deny users.",
e9a17296 1104 filename, linenum);
680cee3b 1105 options->deny_users[options->num_deny_users++] =
1106 xstrdup(arg);
e9a17296 1107 }
1108 break;
3c0ef626 1109
e9a17296 1110 case sAllowGroups:
1111 while ((arg = strdelim(&cp)) && *arg != '\0') {
1112 if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
1113 fatal("%s line %d: too many allow groups.",
1114 filename, linenum);
680cee3b 1115 options->allow_groups[options->num_allow_groups++] =
1116 xstrdup(arg);
e9a17296 1117 }
1118 break;
3c0ef626 1119
e9a17296 1120 case sDenyGroups:
1121 while ((arg = strdelim(&cp)) && *arg != '\0') {
1122 if (options->num_deny_groups >= MAX_DENY_GROUPS)
1123 fatal("%s line %d: too many deny groups.",
1124 filename, linenum);
1125 options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
1126 }
1127 break;
1128
1129 case sCiphers:
1130 arg = strdelim(&cp);
1131 if (!arg || *arg == '\0')
1132 fatal("%s line %d: Missing argument.", filename, linenum);
1133 if (!ciphers_valid(arg))
1134 fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1135 filename, linenum, arg ? arg : "<NONE>");
1136 if (options->ciphers == NULL)
1137 options->ciphers = xstrdup(arg);
1138 break;
1139
1140 case sMacs:
1141 arg = strdelim(&cp);
1142 if (!arg || *arg == '\0')
1143 fatal("%s line %d: Missing argument.", filename, linenum);
1144 if (!mac_valid(arg))
1145 fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1146 filename, linenum, arg ? arg : "<NONE>");
1147 if (options->macs == NULL)
1148 options->macs = xstrdup(arg);
1149 break;
1150
1151 case sProtocol:
1152 intptr = &options->protocol;
1153 arg = strdelim(&cp);
1154 if (!arg || *arg == '\0')
1155 fatal("%s line %d: Missing argument.", filename, linenum);
1156 value = proto_spec(arg);
1157 if (value == SSH_PROTO_UNKNOWN)
1158 fatal("%s line %d: Bad protocol spec '%s'.",
1159 filename, linenum, arg ? arg : "<NONE>");
1160 if (*intptr == SSH_PROTO_UNKNOWN)
1161 *intptr = value;
1162 break;
1163
1164 case sSubsystem:
1165 if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1166 fatal("%s line %d: too many subsystems defined.",
1167 filename, linenum);
1168 }
1169 arg = strdelim(&cp);
1170 if (!arg || *arg == '\0')
1171 fatal("%s line %d: Missing subsystem name.",
1172 filename, linenum);
9108f8d9 1173 if (!*activep) {
1174 arg = strdelim(&cp);
1175 break;
1176 }
e9a17296 1177 for (i = 0; i < options->num_subsystems; i++)
1178 if (strcmp(arg, options->subsystem_name[i]) == 0)
1179 fatal("%s line %d: Subsystem '%s' already defined.",
1180 filename, linenum, arg);
1181 options->subsystem_name[options->num_subsystems] = xstrdup(arg);
1182 arg = strdelim(&cp);
1183 if (!arg || *arg == '\0')
1184 fatal("%s line %d: Missing subsystem command.",
1185 filename, linenum);
1186 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
9108f8d9 1187
1188 /* Collect arguments (separate to executable) */
1189 p = xstrdup(arg);
1190 len = strlen(p) + 1;
1191 while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1192 len += 1 + strlen(arg);
1193 p = xrealloc(p, 1, len);
1194 strlcat(p, " ", len);
1195 strlcat(p, arg, len);
1196 }
1197 options->subsystem_args[options->num_subsystems] = p;
e9a17296 1198 options->num_subsystems++;
1199 break;
1200
1201 case sMaxStartups:
1202 arg = strdelim(&cp);
1203 if (!arg || *arg == '\0')
1204 fatal("%s line %d: Missing MaxStartups spec.",
1205 filename, linenum);
1206 if ((n = sscanf(arg, "%d:%d:%d",
1207 &options->max_startups_begin,
1208 &options->max_startups_rate,
1209 &options->max_startups)) == 3) {
1210 if (options->max_startups_begin >
1211 options->max_startups ||
1212 options->max_startups_rate > 100 ||
1213 options->max_startups_rate < 1)
3c0ef626 1214 fatal("%s line %d: Illegal MaxStartups spec.",
1215 filename, linenum);
e9a17296 1216 } else if (n != 1)
1217 fatal("%s line %d: Illegal MaxStartups spec.",
1218 filename, linenum);
1219 else
1220 options->max_startups = options->max_startups_begin;
1221 break;
1222
c9f39d2c 1223 case sMaxAuthTries:
1224 intptr = &options->max_authtries;
1225 goto parse_int;
1226
22616013 1227 case sMaxSessions:
1228 intptr = &options->max_sessions;
1229 goto parse_int;
1230
e9a17296 1231 case sBanner:
1232 charptr = &options->banner;
1233 goto parse_filename;
47686178 1234
e9a17296 1235 /*
1236 * These options can contain %X options expanded at
1237 * connect time, so that you can specify paths like:
1238 *
1239 * AuthorizedKeysFile /etc/ssh_keys/%u
1240 */
1241 case sAuthorizedKeysFile:
1242 case sAuthorizedKeysFile2:
9108f8d9 1243 charptr = (opcode == sAuthorizedKeysFile) ?
e9a17296 1244 &options->authorized_keys_file :
1245 &options->authorized_keys_file2;
1246 goto parse_filename;
1247
1248 case sClientAliveInterval:
1249 intptr = &options->client_alive_interval;
1250 goto parse_time;
1251
1252 case sClientAliveCountMax:
1253 intptr = &options->client_alive_count_max;
1254 goto parse_int;
1255
c9f39d2c 1256 case sAcceptEnv:
1257 while ((arg = strdelim(&cp)) && *arg != '\0') {
1258 if (strchr(arg, '=') != NULL)
1259 fatal("%s line %d: Invalid environment name.",
1260 filename, linenum);
1261 if (options->num_accept_env >= MAX_ACCEPT_ENV)
1262 fatal("%s line %d: too many allow env.",
1263 filename, linenum);
9108f8d9 1264 if (!*activep)
1265 break;
c9f39d2c 1266 options->accept_env[options->num_accept_env++] =
1267 xstrdup(arg);
1268 }
1269 break;
1270
2c06c99b 1271 case sPermitTunnel:
1272 intptr = &options->permit_tun;
1273 arg = strdelim(&cp);
1274 if (!arg || *arg == '\0')
1275 fatal("%s line %d: Missing yes/point-to-point/"
1276 "ethernet/no argument.", filename, linenum);
22616013 1277 value = -1;
1278 for (i = 0; tunmode_desc[i].val != -1; i++)
1279 if (strcmp(tunmode_desc[i].text, arg) == 0) {
1280 value = tunmode_desc[i].val;
1281 break;
1282 }
1283 if (value == -1)
2c06c99b 1284 fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1285 "no argument: %s", filename, linenum, arg);
1286 if (*intptr == -1)
1287 *intptr = value;
1288 break;
1289
9108f8d9 1290 case sMatch:
1291 if (cmdline)
1292 fatal("Match directive not supported as a command-line "
1293 "option");
1294 value = match_cfg_line(&cp, linenum, user, host, address);
1295 if (value < 0)
1296 fatal("%s line %d: Bad Match condition", filename,
1297 linenum);
1298 *activep = value;
1299 break;
1300
1301 case sPermitOpen:
1302 arg = strdelim(&cp);
1303 if (!arg || *arg == '\0')
1304 fatal("%s line %d: missing PermitOpen specification",
1305 filename, linenum);
799ae497 1306 n = options->num_permitted_opens; /* modified later */
9108f8d9 1307 if (strcmp(arg, "any") == 0) {
799ae497 1308 if (*activep && n == -1) {
9108f8d9 1309 channel_clear_adm_permitted_opens();
1310 options->num_permitted_opens = 0;
1311 }
1312 break;
1313 }
799ae497 1314 if (*activep && n == -1)
1315 channel_clear_adm_permitted_opens();
9108f8d9 1316 for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1317 p = hpdelim(&arg);
1318 if (p == NULL)
1319 fatal("%s line %d: missing host in PermitOpen",
1320 filename, linenum);
1321 p = cleanhostname(p);
1322 if (arg == NULL || (port = a2port(arg)) == 0)
1323 fatal("%s line %d: bad port number in "
1324 "PermitOpen", filename, linenum);
799ae497 1325 if (*activep && n == -1)
9108f8d9 1326 options->num_permitted_opens =
1327 channel_add_adm_permitted_opens(p, port);
9108f8d9 1328 }
1329 break;
1330
1331 case sForceCommand:
1332 if (cp == NULL)
1333 fatal("%.200s line %d: Missing argument.", filename,
1334 linenum);
1335 len = strspn(cp, WHITESPACE);
1336 if (*activep && options->adm_forced_command == NULL)
1337 options->adm_forced_command = xstrdup(cp + len);
1338 return 0;
1339
47686178 1340 case sChrootDirectory:
1341 charptr = &options->chroot_directory;
1342
1343 arg = strdelim(&cp);
1344 if (!arg || *arg == '\0')
1345 fatal("%s line %d: missing file name.",
1346 filename, linenum);
1347 if (*activep && *charptr == NULL)
1348 *charptr = xstrdup(arg);
1349 break;
1350
e9a17296 1351 case sDeprecated:
0fff78ff 1352 logit("%s line %d: Deprecated option %s",
1353 filename, linenum, arg);
1354 while (arg)
1355 arg = strdelim(&cp);
1356 break;
1357
1358 case sUnsupported:
1359 logit("%s line %d: Unsupported option %s",
e9a17296 1360 filename, linenum, arg);
1361 while (arg)
1362 arg = strdelim(&cp);
1363 break;
1364
1365 default:
1366 fatal("%s line %d: Missing handler for opcode %s (%d)",
1367 filename, linenum, arg, opcode);
1368 }
1369 if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
1370 fatal("%s line %d: garbage at end of line; \"%.200s\".",
1371 filename, linenum, arg);
1372 return 0;
1373}
3c0ef626 1374
e9a17296 1375/* Reads the server configuration file. */
3c0ef626 1376
e9a17296 1377void
c9f39d2c 1378load_server_config(const char *filename, Buffer *conf)
e9a17296 1379{
c9f39d2c 1380 char line[1024], *cp;
680cee3b 1381 FILE *f;
e9a17296 1382
c9f39d2c 1383 debug2("%s: filename %s", __func__, filename);
1384 if ((f = fopen(filename, "r")) == NULL) {
e9a17296 1385 perror(filename);
1386 exit(1);
1387 }
c9f39d2c 1388 buffer_clear(conf);
e9a17296 1389 while (fgets(line, sizeof(line), f)) {
c9f39d2c 1390 /*
1391 * Trim out comments and strip whitespace
1392 * NB - preserve newlines, they are needed to reproduce
1393 * line numbers later for error messages
1394 */
1395 if ((cp = strchr(line, '#')) != NULL)
1396 memcpy(cp, "\n", 2);
1397 cp = line + strspn(line, " \t\r");
1398
1399 buffer_append(conf, cp, strlen(cp));
3c0ef626 1400 }
c9f39d2c 1401 buffer_append(conf, "\0", 1);
3c0ef626 1402 fclose(f);
c9f39d2c 1403 debug2("%s: done config len = %d", __func__, buffer_len(conf));
1404}
1405
1406void
9108f8d9 1407parse_server_match_config(ServerOptions *options, const char *user,
1408 const char *host, const char *address)
1409{
1410 ServerOptions mo;
1411
1412 initialize_server_options(&mo);
1413 parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
799ae497 1414 copy_set_server_options(options, &mo, 0);
9108f8d9 1415}
1416
799ae497 1417/* Helper macros */
1418#define M_CP_INTOPT(n) do {\
1419 if (src->n != -1) \
1420 dst->n = src->n; \
1421} while (0)
1422#define M_CP_STROPT(n) do {\
1423 if (src->n != NULL) { \
1424 if (dst->n != NULL) \
1425 xfree(dst->n); \
1426 dst->n = src->n; \
1427 } \
1428} while(0)
1429
1430/*
1431 * Copy any supported values that are set.
1432 *
1433 * If the preauth flag is set, we do not bother copying the the string or
1434 * array values that are not used pre-authentication, because any that we
1435 * do use must be explictly sent in mm_getpwnamallow().
1436 */
9108f8d9 1437void
799ae497 1438copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
9108f8d9 1439{
799ae497 1440 M_CP_INTOPT(password_authentication);
1441 M_CP_INTOPT(gss_authentication);
1442 M_CP_INTOPT(rsa_authentication);
1443 M_CP_INTOPT(pubkey_authentication);
1444 M_CP_INTOPT(kerberos_authentication);
1445 M_CP_INTOPT(hostbased_authentication);
1446 M_CP_INTOPT(kbd_interactive_authentication);
47686178 1447 M_CP_INTOPT(permit_root_login);
799ae497 1448
1449 M_CP_INTOPT(allow_tcp_forwarding);
22616013 1450 M_CP_INTOPT(allow_agent_forwarding);
799ae497 1451 M_CP_INTOPT(gateway_ports);
1452 M_CP_INTOPT(x11_display_offset);
1453 M_CP_INTOPT(x11_forwarding);
1454 M_CP_INTOPT(x11_use_localhost);
22616013 1455 M_CP_INTOPT(max_sessions);
1456 M_CP_INTOPT(max_authtries);
799ae497 1457
1458 M_CP_STROPT(banner);
1459 if (preauth)
1460 return;
1461 M_CP_STROPT(adm_forced_command);
47686178 1462 M_CP_STROPT(chroot_directory);
9108f8d9 1463}
1464
799ae497 1465#undef M_CP_INTOPT
1466#undef M_CP_STROPT
1467
9108f8d9 1468void
1469parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1470 const char *user, const char *host, const char *address)
c9f39d2c 1471{
9108f8d9 1472 int active, linenum, bad_options = 0;
c9f39d2c 1473 char *cp, *obuf, *cbuf;
1474
1475 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1476
1477 obuf = cbuf = xstrdup(buffer_ptr(conf));
9108f8d9 1478 active = user ? 0 : 1;
c9f39d2c 1479 linenum = 1;
dec6d9fe 1480 while ((cp = strsep(&cbuf, "\n")) != NULL) {
c9f39d2c 1481 if (process_server_config_line(options, cp, filename,
9108f8d9 1482 linenum++, &active, user, host, address) != 0)
c9f39d2c 1483 bad_options++;
1484 }
1485 xfree(obuf);
3c0ef626 1486 if (bad_options > 0)
1487 fatal("%s: terminating, %d bad configuration options",
1488 filename, bad_options);
1489}
22616013 1490
1491static const char *
1492fmt_intarg(ServerOpCodes code, int val)
1493{
1494 if (code == sAddressFamily) {
1495 switch (val) {
1496 case AF_INET:
1497 return "inet";
1498 case AF_INET6:
1499 return "inet6";
1500 case AF_UNSPEC:
1501 return "any";
1502 default:
1503 return "UNKNOWN";
1504 }
1505 }
1506 if (code == sPermitRootLogin) {
1507 switch (val) {
1508 case PERMIT_NO_PASSWD:
1509 return "without-passord";
1510 case PERMIT_FORCED_ONLY:
1511 return "forced-commands-only";
1512 case PERMIT_YES:
1513 return "yes";
1514 }
1515 }
1516 if (code == sProtocol) {
1517 switch (val) {
1518 case SSH_PROTO_1:
1519 return "1";
1520 case SSH_PROTO_2:
1521 return "2";
1522 case (SSH_PROTO_1|SSH_PROTO_2):
1523 return "2,1";
1524 default:
1525 return "UNKNOWN";
1526 }
1527 }
1528 if (code == sGatewayPorts && val == 2)
1529 return "clientspecified";
1530 if (code == sCompression && val == COMP_DELAYED)
1531 return "delayed";
1532 switch (val) {
1533 case -1:
1534 return "unset";
1535 case 0:
1536 return "no";
1537 case 1:
1538 return "yes";
1539 }
1540 return "UNKNOWN";
1541}
1542
1543static const char *
1544lookup_opcode_name(ServerOpCodes code)
1545{
1546 u_int i;
1547
1548 for (i = 0; keywords[i].name != NULL; i++)
1549 if (keywords[i].opcode == code)
1550 return(keywords[i].name);
1551 return "UNKNOWN";
1552}
1553
1554static void
1555dump_cfg_int(ServerOpCodes code, int val)
1556{
1557 printf("%s %d\n", lookup_opcode_name(code), val);
1558}
1559
1560static void
1561dump_cfg_fmtint(ServerOpCodes code, int val)
1562{
1563 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
1564}
1565
1566static void
1567dump_cfg_string(ServerOpCodes code, const char *val)
1568{
1569 if (val == NULL)
1570 return;
1571 printf("%s %s\n", lookup_opcode_name(code), val);
1572}
1573
1574static void
1575dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
1576{
1577 u_int i;
1578
1579 for (i = 0; i < count; i++)
1580 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
1581}
1582
1583void
1584dump_config(ServerOptions *o)
1585{
1586 u_int i;
1587 int ret;
1588 struct addrinfo *ai;
1589 char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
1590
1591 /* these are usually at the top of the config */
1592 for (i = 0; i < o->num_ports; i++)
1593 printf("port %d\n", o->ports[i]);
1594 dump_cfg_fmtint(sProtocol, o->protocol);
1595 dump_cfg_fmtint(sAddressFamily, o->address_family);
1596
1597 /* ListenAddress must be after Port */
1598 for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
1599 if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
1600 sizeof(addr), port, sizeof(port),
1601 NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
1602 error("getnameinfo failed: %.100s",
1603 (ret != EAI_SYSTEM) ? gai_strerror(ret) :
1604 strerror(errno));
1605 } else {
1606 if (ai->ai_family == AF_INET6)
1607 printf("listenaddress [%s]:%s\n", addr, port);
1608 else
1609 printf("listenaddress %s:%s\n", addr, port);
1610 }
1611 }
1612
1613 /* integer arguments */
1614 dump_cfg_int(sServerKeyBits, o->server_key_bits);
1615 dump_cfg_int(sLoginGraceTime, o->login_grace_time);
1616 dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
1617 dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
1618 dump_cfg_int(sMaxAuthTries, o->max_authtries);
1619 dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
1620 dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
1621
1622 /* formatted integer arguments */
1623 dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
1624 dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
1625 dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
1626 dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
1627 dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
1628 dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
1629 o->hostbased_uses_name_from_packet_only);
1630 dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
1631 dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
1632 dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
1633 dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
1634 dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
1635 dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
1636 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
1637 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
1638 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
1639 dump_cfg_fmtint(sKbdInteractiveAuthentication,
1640 o->kbd_interactive_authentication);
1641 dump_cfg_fmtint(sChallengeResponseAuthentication,
1642 o->challenge_response_authentication);
1643 dump_cfg_fmtint(sPrintMotd, o->print_motd);
1644 dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
1645 dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
1646 dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
1647 dump_cfg_fmtint(sStrictModes, o->strict_modes);
1648 dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
1649 dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
1650 dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
1651 dump_cfg_fmtint(sUseLogin, o->use_login);
1652 dump_cfg_fmtint(sCompression, o->compression);
1653 dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
1654 dump_cfg_fmtint(sUseDNS, o->use_dns);
1655 dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
1656 dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
1657
1658 /* string arguments */
1659 dump_cfg_string(sPidFile, o->pid_file);
1660 dump_cfg_string(sXAuthLocation, o->xauth_location);
1661 dump_cfg_string(sCiphers, o->ciphers);
1662 dump_cfg_string(sMacs, o->macs);
1663 dump_cfg_string(sBanner, o->banner);
1664 dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
1665 dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
1666 dump_cfg_string(sForceCommand, o->adm_forced_command);
1667
1668 /* string arguments requiring a lookup */
1669 dump_cfg_string(sLogLevel, log_level_name(o->log_level));
1670 dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
1671
1672 /* string array arguments */
1673 dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
1674 o->host_key_files);
1675 dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
1676 dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
1677 dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
1678 dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
1679 dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
1680
1681 /* other arguments */
1682 for (i = 0; i < o->num_subsystems; i++)
1683 printf("subsystem %s %s\n", o->subsystem_name[i],
1684 o->subsystem_args[i]);
1685
1686 printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
1687 o->max_startups_rate, o->max_startups);
1688
1689 for (i = 0; tunmode_desc[i].val != -1; i++)
1690 if (tunmode_desc[i].val == o->permit_tun) {
1691 s = tunmode_desc[i].text;
1692 break;
1693 }
1694 dump_cfg_string(sPermitTunnel, s);
1695
1696 printf("permitopen");
1697 channel_print_adm_permitted_opens();
1698 printf("\n");
1699}
This page took 0.333398 seconds and 5 git commands to generate.