xref: /onnv-gate/usr/src/cmd/ssh/sshd/servconf.c (revision 11060:40daac51fc0c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
30Sstevel@tonic-gate  *                    All rights reserved
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
60Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
70Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
80Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
90Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
100Sstevel@tonic-gate  */
110Sstevel@tonic-gate /*
129139SJan.Pechanec@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
130Sstevel@tonic-gate  * Use is subject to license terms.
140Sstevel@tonic-gate  */
150Sstevel@tonic-gate 
160Sstevel@tonic-gate #include "includes.h"
170Sstevel@tonic-gate RCSID("$OpenBSD: servconf.c,v 1.115 2002/09/04 18:52:42 stevesk Exp $");
180Sstevel@tonic-gate 
190Sstevel@tonic-gate #ifdef HAVE_DEFOPEN
200Sstevel@tonic-gate #include <deflt.h>
210Sstevel@tonic-gate #endif /* HAVE_DEFOPEN */
220Sstevel@tonic-gate 
230Sstevel@tonic-gate #if defined(KRB4)
240Sstevel@tonic-gate #include <krb.h>
250Sstevel@tonic-gate #endif
260Sstevel@tonic-gate #if defined(KRB5)
270Sstevel@tonic-gate #ifdef HEIMDAL
280Sstevel@tonic-gate #include <krb.h>
290Sstevel@tonic-gate #else
300Sstevel@tonic-gate /* Bodge - but then, so is using the kerberos IV KEYFILE to get a Kerberos V
310Sstevel@tonic-gate  * keytab */
320Sstevel@tonic-gate #define KEYFILE "/etc/krb5.keytab"
330Sstevel@tonic-gate #endif
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate #ifdef AFS
360Sstevel@tonic-gate #include <kafs.h>
370Sstevel@tonic-gate #endif
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include "ssh.h"
400Sstevel@tonic-gate #include "log.h"
4111044SHuie-Ying.Lee@Sun.COM #include "buffer.h"
420Sstevel@tonic-gate #include "servconf.h"
430Sstevel@tonic-gate #include "xmalloc.h"
440Sstevel@tonic-gate #include "compat.h"
450Sstevel@tonic-gate #include "pathnames.h"
460Sstevel@tonic-gate #include "tildexpand.h"
470Sstevel@tonic-gate #include "misc.h"
480Sstevel@tonic-gate #include "cipher.h"
490Sstevel@tonic-gate #include "kex.h"
500Sstevel@tonic-gate #include "mac.h"
510Sstevel@tonic-gate #include "auth.h"
5211044SHuie-Ying.Lee@Sun.COM #include "match.h"
5311044SHuie-Ying.Lee@Sun.COM #include "groupaccess.h"
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static void add_listen_addr(ServerOptions *, char *, u_short);
560Sstevel@tonic-gate static void add_one_listen_addr(ServerOptions *, char *, u_short);
570Sstevel@tonic-gate 
5811044SHuie-Ying.Lee@Sun.COM extern Buffer cfg;
5911044SHuie-Ying.Lee@Sun.COM 
600Sstevel@tonic-gate /* AF_UNSPEC or AF_INET or AF_INET6 */
610Sstevel@tonic-gate extern int IPv4or6;
620Sstevel@tonic-gate 
639139SJan.Pechanec@Sun.COM /*
649139SJan.Pechanec@Sun.COM  * Initializes the server options to their initial (unset) values. Some of those
659139SJan.Pechanec@Sun.COM  * that stay unset after the command line options and configuration files are
669139SJan.Pechanec@Sun.COM  * read are set to their default values in fill_default_server_options().
679139SJan.Pechanec@Sun.COM  */
680Sstevel@tonic-gate void
690Sstevel@tonic-gate initialize_server_options(ServerOptions *options)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	(void) memset(options, 0, sizeof(*options));
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	/* Portable-specific options */
740Sstevel@tonic-gate 	options->pam_authentication_via_kbd_int = -1;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	/* Standard Options */
770Sstevel@tonic-gate 	options->num_ports = 0;
780Sstevel@tonic-gate 	options->ports_from_cmdline = 0;
790Sstevel@tonic-gate 	options->listen_addrs = NULL;
800Sstevel@tonic-gate 	options->num_host_key_files = 0;
810Sstevel@tonic-gate 	options->pid_file = NULL;
820Sstevel@tonic-gate 	options->server_key_bits = -1;
830Sstevel@tonic-gate 	options->login_grace_time = -1;
840Sstevel@tonic-gate 	options->key_regeneration_time = -1;
850Sstevel@tonic-gate 	options->permit_root_login = PERMIT_NOT_SET;
860Sstevel@tonic-gate 	options->ignore_rhosts = -1;
870Sstevel@tonic-gate 	options->ignore_user_known_hosts = -1;
880Sstevel@tonic-gate 	options->print_motd = -1;
890Sstevel@tonic-gate 	options->print_lastlog = -1;
900Sstevel@tonic-gate 	options->x11_forwarding = -1;
910Sstevel@tonic-gate 	options->x11_display_offset = -1;
920Sstevel@tonic-gate 	options->x11_use_localhost = -1;
930Sstevel@tonic-gate 	options->xauth_location = NULL;
940Sstevel@tonic-gate 	options->strict_modes = -1;
950Sstevel@tonic-gate 	options->keepalives = -1;
960Sstevel@tonic-gate 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
970Sstevel@tonic-gate 	options->log_level = SYSLOG_LEVEL_NOT_SET;
980Sstevel@tonic-gate 	options->rhosts_authentication = -1;
990Sstevel@tonic-gate 	options->rhosts_rsa_authentication = -1;
1000Sstevel@tonic-gate 	options->hostbased_authentication = -1;
1010Sstevel@tonic-gate 	options->hostbased_uses_name_from_packet_only = -1;
1020Sstevel@tonic-gate 	options->rsa_authentication = -1;
1030Sstevel@tonic-gate 	options->pubkey_authentication = -1;
1040Sstevel@tonic-gate #ifdef GSSAPI
1050Sstevel@tonic-gate 	options->gss_authentication = -1;
1060Sstevel@tonic-gate 	options->gss_keyex = -1;
1070Sstevel@tonic-gate 	options->gss_store_creds = -1;
1080Sstevel@tonic-gate 	options->gss_use_session_ccache = -1;
1090Sstevel@tonic-gate 	options->gss_cleanup_creds = -1;
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
1120Sstevel@tonic-gate 	options->kerberos_authentication = -1;
1130Sstevel@tonic-gate 	options->kerberos_or_local_passwd = -1;
1140Sstevel@tonic-gate 	options->kerberos_ticket_cleanup = -1;
1150Sstevel@tonic-gate #endif
1160Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
1170Sstevel@tonic-gate 	options->kerberos_tgt_passing = -1;
1180Sstevel@tonic-gate #endif
1190Sstevel@tonic-gate #ifdef AFS
1200Sstevel@tonic-gate 	options->afs_token_passing = -1;
1210Sstevel@tonic-gate #endif
1220Sstevel@tonic-gate 	options->password_authentication = -1;
1230Sstevel@tonic-gate 	options->kbd_interactive_authentication = -1;
1240Sstevel@tonic-gate 	options->challenge_response_authentication = -1;
1250Sstevel@tonic-gate 	options->permit_empty_passwd = -1;
1260Sstevel@tonic-gate 	options->permit_user_env = -1;
1270Sstevel@tonic-gate 	options->compression = -1;
1280Sstevel@tonic-gate 	options->allow_tcp_forwarding = -1;
1290Sstevel@tonic-gate 	options->num_allow_users = 0;
1300Sstevel@tonic-gate 	options->num_deny_users = 0;
1310Sstevel@tonic-gate 	options->num_allow_groups = 0;
1320Sstevel@tonic-gate 	options->num_deny_groups = 0;
1330Sstevel@tonic-gate 	options->ciphers = NULL;
1340Sstevel@tonic-gate 	options->macs = NULL;
1350Sstevel@tonic-gate 	options->protocol = SSH_PROTO_UNKNOWN;
1360Sstevel@tonic-gate 	options->gateway_ports = -1;
1370Sstevel@tonic-gate 	options->num_subsystems = 0;
1380Sstevel@tonic-gate 	options->max_startups_begin = -1;
1390Sstevel@tonic-gate 	options->max_startups_rate = -1;
1400Sstevel@tonic-gate 	options->max_startups = -1;
1410Sstevel@tonic-gate 	options->banner = NULL;
1420Sstevel@tonic-gate 	options->verify_reverse_mapping = -1;
1430Sstevel@tonic-gate 	options->client_alive_interval = -1;
1440Sstevel@tonic-gate 	options->client_alive_count_max = -1;
1450Sstevel@tonic-gate 	options->authorized_keys_file = NULL;
1460Sstevel@tonic-gate 	options->authorized_keys_file2 = NULL;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	options->max_auth_tries = -1;
1490Sstevel@tonic-gate 	options->max_auth_tries_log = -1;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	options->max_init_auth_tries = -1;
1520Sstevel@tonic-gate 	options->max_init_auth_tries_log = -1;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	options->lookup_client_hostnames = -1;
1557574SJan.Pechanec@Sun.COM 	options->use_openssl_engine = -1;
1569139SJan.Pechanec@Sun.COM 	options->chroot_directory = NULL;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate #ifdef HAVE_DEFOPEN
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate  * Reads /etc/default/login and defaults several ServerOptions:
1620Sstevel@tonic-gate  *
1630Sstevel@tonic-gate  * PermitRootLogin
1640Sstevel@tonic-gate  * PermitEmptyPasswords
1650Sstevel@tonic-gate  * LoginGraceTime
1660Sstevel@tonic-gate  *
1670Sstevel@tonic-gate  * CONSOLE=*      -> PermitRootLogin=without-password
1680Sstevel@tonic-gate  * #CONSOLE=*     -> PermitRootLogin=yes
1690Sstevel@tonic-gate  *
1700Sstevel@tonic-gate  * PASSREQ=YES    -> PermitEmptyPasswords=no
1710Sstevel@tonic-gate  * PASSREQ=NO     -> PermitEmptyPasswords=yes
1720Sstevel@tonic-gate  * #PASSREQ=*     -> PermitEmptyPasswords=no
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  * TIMEOUT=<secs> -> LoginGraceTime=<secs>
1750Sstevel@tonic-gate  * #TIMEOUT=<secs> -> LoginGraceTime=300
1760Sstevel@tonic-gate  */
1770Sstevel@tonic-gate static
1780Sstevel@tonic-gate void
1790Sstevel@tonic-gate deflt_fill_default_server_options(ServerOptions *options)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	int	flags;
1820Sstevel@tonic-gate 	char	*ptr;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (defopen(_PATH_DEFAULT_LOGIN))
1850Sstevel@tonic-gate 		return;
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	/* Ignore case */
1880Sstevel@tonic-gate 	flags = defcntl(DC_GETFLAGS, 0);
1890Sstevel@tonic-gate 	TURNOFF(flags, DC_CASE);
1900Sstevel@tonic-gate 	(void) defcntl(DC_SETFLAGS, flags);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (options->permit_root_login == PERMIT_NOT_SET &&
1930Sstevel@tonic-gate 	    (ptr = defread("CONSOLE=")) != NULL)
1940Sstevel@tonic-gate 		options->permit_root_login = PERMIT_NO_PASSWD;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	if (options->permit_empty_passwd == -1 &&
1970Sstevel@tonic-gate 	    (ptr = defread("PASSREQ=")) != NULL) {
1980Sstevel@tonic-gate 		if (strcasecmp("YES", ptr) == 0)
1990Sstevel@tonic-gate 			options->permit_empty_passwd = 0;
2000Sstevel@tonic-gate 		else if (strcasecmp("NO", ptr) == 0)
2010Sstevel@tonic-gate 			options->permit_empty_passwd = 1;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (options->max_init_auth_tries == -1 &&
2050Sstevel@tonic-gate 	    (ptr = defread("RETRIES=")) != NULL) {
2060Sstevel@tonic-gate 		options->max_init_auth_tries = atoi(ptr);
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	if (options->max_init_auth_tries_log == -1 &&
2100Sstevel@tonic-gate 	    (ptr = defread("SYSLOG_FAILED_LOGINS=")) != NULL) {
2110Sstevel@tonic-gate 		options->max_init_auth_tries_log = atoi(ptr);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (options->login_grace_time == -1) {
2150Sstevel@tonic-gate 		if ((ptr = defread("TIMEOUT=")) != NULL)
2160Sstevel@tonic-gate 			options->login_grace_time = (unsigned)atoi(ptr);
2170Sstevel@tonic-gate 		else
2180Sstevel@tonic-gate 			options->login_grace_time = 300;
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	(void) defopen((char *)NULL);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate #endif /* HAVE_DEFOPEN */
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate void
2260Sstevel@tonic-gate fill_default_server_options(ServerOptions *options)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate #ifdef HAVE_DEFOPEN
2300Sstevel@tonic-gate 	deflt_fill_default_server_options(options);
2310Sstevel@tonic-gate #endif /* HAVE_DEFOPEN */
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/* Portable-specific options */
2340Sstevel@tonic-gate 	if (options->pam_authentication_via_kbd_int == -1)
2350Sstevel@tonic-gate 		options->pam_authentication_via_kbd_int = 0;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	/* Standard Options */
2380Sstevel@tonic-gate 	if (options->protocol == SSH_PROTO_UNKNOWN)
2390Sstevel@tonic-gate 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
2400Sstevel@tonic-gate 	if (options->num_host_key_files == 0) {
2410Sstevel@tonic-gate 		/* fill default hostkeys for protocols */
2420Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_1)
2430Sstevel@tonic-gate 			options->host_key_files[options->num_host_key_files++] =
2440Sstevel@tonic-gate 			    _PATH_HOST_KEY_FILE;
2450Sstevel@tonic-gate #ifndef GSSAPI
2460Sstevel@tonic-gate 		/* With GSS keyex we can run v2 w/ no host keys */
2470Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_2) {
2480Sstevel@tonic-gate 			options->host_key_files[options->num_host_key_files++] =
2490Sstevel@tonic-gate 			    _PATH_HOST_RSA_KEY_FILE;
2500Sstevel@tonic-gate 			options->host_key_files[options->num_host_key_files++] =
2510Sstevel@tonic-gate 			    _PATH_HOST_DSA_KEY_FILE;
2520Sstevel@tonic-gate 		}
2530Sstevel@tonic-gate #endif /* GSSAPI */
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 	if (options->num_ports == 0)
2560Sstevel@tonic-gate 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
2570Sstevel@tonic-gate 	if (options->listen_addrs == NULL)
2580Sstevel@tonic-gate 		add_listen_addr(options, NULL, 0);
2590Sstevel@tonic-gate 	if (options->pid_file == NULL)
2600Sstevel@tonic-gate 		options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
2610Sstevel@tonic-gate 	if (options->server_key_bits == -1)
2620Sstevel@tonic-gate 		options->server_key_bits = 768;
2630Sstevel@tonic-gate 	if (options->login_grace_time == -1)
2640Sstevel@tonic-gate 		options->login_grace_time = 120;
2650Sstevel@tonic-gate 	if (options->key_regeneration_time == -1)
2660Sstevel@tonic-gate 		options->key_regeneration_time = 3600;
2670Sstevel@tonic-gate 	if (options->permit_root_login == PERMIT_NOT_SET)
2680Sstevel@tonic-gate 		options->permit_root_login = PERMIT_YES;
2690Sstevel@tonic-gate 	if (options->ignore_rhosts == -1)
2700Sstevel@tonic-gate 		options->ignore_rhosts = 1;
2710Sstevel@tonic-gate 	if (options->ignore_user_known_hosts == -1)
2720Sstevel@tonic-gate 		options->ignore_user_known_hosts = 0;
2730Sstevel@tonic-gate 	if (options->print_motd == -1)
2740Sstevel@tonic-gate 		options->print_motd = 1;
2750Sstevel@tonic-gate 	if (options->print_lastlog == -1)
2760Sstevel@tonic-gate 		options->print_lastlog = 1;
2770Sstevel@tonic-gate 	if (options->x11_forwarding == -1)
2780Sstevel@tonic-gate 		options->x11_forwarding = 1;
2790Sstevel@tonic-gate 	if (options->x11_display_offset == -1)
2800Sstevel@tonic-gate 		options->x11_display_offset = 10;
2810Sstevel@tonic-gate 	if (options->x11_use_localhost == -1)
2820Sstevel@tonic-gate 		options->x11_use_localhost = 1;
2830Sstevel@tonic-gate 	if (options->xauth_location == NULL)
2840Sstevel@tonic-gate 		options->xauth_location = _PATH_XAUTH;
2850Sstevel@tonic-gate 	if (options->strict_modes == -1)
2860Sstevel@tonic-gate 		options->strict_modes = 1;
2870Sstevel@tonic-gate 	if (options->keepalives == -1)
2880Sstevel@tonic-gate 		options->keepalives = 1;
2890Sstevel@tonic-gate 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2900Sstevel@tonic-gate 		options->log_facility = SYSLOG_FACILITY_AUTH;
2910Sstevel@tonic-gate 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2920Sstevel@tonic-gate 		options->log_level = SYSLOG_LEVEL_INFO;
2930Sstevel@tonic-gate 	if (options->rhosts_authentication == -1)
2940Sstevel@tonic-gate 		options->rhosts_authentication = 0;
2950Sstevel@tonic-gate 	if (options->rhosts_rsa_authentication == -1)
2960Sstevel@tonic-gate 		options->rhosts_rsa_authentication = 0;
2970Sstevel@tonic-gate 	if (options->hostbased_authentication == -1)
2980Sstevel@tonic-gate 		options->hostbased_authentication = 0;
2990Sstevel@tonic-gate 	if (options->hostbased_uses_name_from_packet_only == -1)
3000Sstevel@tonic-gate 		options->hostbased_uses_name_from_packet_only = 0;
3010Sstevel@tonic-gate 	if (options->rsa_authentication == -1)
3020Sstevel@tonic-gate 		options->rsa_authentication = 1;
3030Sstevel@tonic-gate 	if (options->pubkey_authentication == -1)
3040Sstevel@tonic-gate 		options->pubkey_authentication = 1;
3050Sstevel@tonic-gate #ifdef GSSAPI
3060Sstevel@tonic-gate 	if (options->gss_authentication == -1)
3070Sstevel@tonic-gate 		options->gss_authentication = 1;
3080Sstevel@tonic-gate 	if (options->gss_keyex == -1)
3090Sstevel@tonic-gate 		options->gss_keyex = 1;
3100Sstevel@tonic-gate 	if (options->gss_store_creds == -1)
3110Sstevel@tonic-gate 		options->gss_store_creds = 1;
3120Sstevel@tonic-gate 	if (options->gss_use_session_ccache == -1)
3130Sstevel@tonic-gate 		options->gss_use_session_ccache = 1;
3140Sstevel@tonic-gate 	if (options->gss_cleanup_creds == -1)
3150Sstevel@tonic-gate 		options->gss_cleanup_creds = 1;
3160Sstevel@tonic-gate #endif
3170Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
3180Sstevel@tonic-gate 	if (options->kerberos_authentication == -1)
3190Sstevel@tonic-gate 		options->kerberos_authentication = 0;
3200Sstevel@tonic-gate 	if (options->kerberos_or_local_passwd == -1)
3210Sstevel@tonic-gate 		options->kerberos_or_local_passwd = 1;
3220Sstevel@tonic-gate 	if (options->kerberos_ticket_cleanup == -1)
3230Sstevel@tonic-gate 		options->kerberos_ticket_cleanup = 1;
3240Sstevel@tonic-gate #endif
3250Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
3260Sstevel@tonic-gate 	if (options->kerberos_tgt_passing == -1)
3270Sstevel@tonic-gate 		options->kerberos_tgt_passing = 0;
3280Sstevel@tonic-gate #endif
3290Sstevel@tonic-gate #ifdef AFS
3300Sstevel@tonic-gate 	if (options->afs_token_passing == -1)
3310Sstevel@tonic-gate 		options->afs_token_passing = 0;
3320Sstevel@tonic-gate #endif
3330Sstevel@tonic-gate 	if (options->password_authentication == -1)
3340Sstevel@tonic-gate 		options->password_authentication = 1;
3350Sstevel@tonic-gate 	if (options->kbd_interactive_authentication == -1)
3360Sstevel@tonic-gate 		options->kbd_interactive_authentication = 0;
3370Sstevel@tonic-gate 	if (options->challenge_response_authentication == -1)
3380Sstevel@tonic-gate 		options->challenge_response_authentication = 1;
3390Sstevel@tonic-gate 	if (options->permit_empty_passwd == -1)
3400Sstevel@tonic-gate 		options->permit_empty_passwd = 0;
3410Sstevel@tonic-gate 	if (options->permit_user_env == -1)
3420Sstevel@tonic-gate 		options->permit_user_env = 0;
3430Sstevel@tonic-gate 	if (options->compression == -1)
3440Sstevel@tonic-gate 		options->compression = 1;
3450Sstevel@tonic-gate 	if (options->allow_tcp_forwarding == -1)
3460Sstevel@tonic-gate 		options->allow_tcp_forwarding = 1;
3470Sstevel@tonic-gate 	if (options->gateway_ports == -1)
3480Sstevel@tonic-gate 		options->gateway_ports = 0;
3490Sstevel@tonic-gate 	if (options->max_startups == -1)
3500Sstevel@tonic-gate 		options->max_startups = 10;
3510Sstevel@tonic-gate 	if (options->max_startups_rate == -1)
3520Sstevel@tonic-gate 		options->max_startups_rate = 100;		/* 100% */
3530Sstevel@tonic-gate 	if (options->max_startups_begin == -1)
3540Sstevel@tonic-gate 		options->max_startups_begin = options->max_startups;
3550Sstevel@tonic-gate 	if (options->verify_reverse_mapping == -1)
3560Sstevel@tonic-gate 		options->verify_reverse_mapping = 0;
3570Sstevel@tonic-gate 	if (options->client_alive_interval == -1)
3580Sstevel@tonic-gate 		options->client_alive_interval = 0;
3590Sstevel@tonic-gate 	if (options->client_alive_count_max == -1)
3600Sstevel@tonic-gate 		options->client_alive_count_max = 3;
3610Sstevel@tonic-gate 	if (options->authorized_keys_file2 == NULL) {
3620Sstevel@tonic-gate 		/* authorized_keys_file2 falls back to authorized_keys_file */
3630Sstevel@tonic-gate 		if (options->authorized_keys_file != NULL)
3640Sstevel@tonic-gate 			options->authorized_keys_file2 = options->authorized_keys_file;
3650Sstevel@tonic-gate 		else
3660Sstevel@tonic-gate 			options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 	if (options->authorized_keys_file == NULL)
3690Sstevel@tonic-gate 		options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	if (options->max_auth_tries == -1)
3720Sstevel@tonic-gate 		options->max_auth_tries = AUTH_FAIL_MAX;
3730Sstevel@tonic-gate 	if (options->max_auth_tries_log == -1)
3740Sstevel@tonic-gate 		options->max_auth_tries_log = options->max_auth_tries / 2;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (options->max_init_auth_tries == -1)
3770Sstevel@tonic-gate 		options->max_init_auth_tries = AUTH_FAIL_MAX;
3780Sstevel@tonic-gate 	if (options->max_init_auth_tries_log == -1)
3790Sstevel@tonic-gate 		options->max_init_auth_tries_log = options->max_init_auth_tries / 2;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (options->lookup_client_hostnames == -1)
3820Sstevel@tonic-gate 		options->lookup_client_hostnames = 1;
3837574SJan.Pechanec@Sun.COM 	if (options->use_openssl_engine == -1)
3847574SJan.Pechanec@Sun.COM 		options->use_openssl_engine = 1;
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate /* Keyword tokens. */
3880Sstevel@tonic-gate typedef enum {
3890Sstevel@tonic-gate 	sBadOption,		/* == unknown option */
3900Sstevel@tonic-gate 	/* Portable-specific options */
3910Sstevel@tonic-gate 	sPAMAuthenticationViaKbdInt,
3920Sstevel@tonic-gate 	/* Standard Options */
3930Sstevel@tonic-gate 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
3940Sstevel@tonic-gate 	sPermitRootLogin, sLogFacility, sLogLevel,
3950Sstevel@tonic-gate 	sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
3960Sstevel@tonic-gate #ifdef GSSAPI
3970Sstevel@tonic-gate 	sGssAuthentication, sGssKeyEx, sGssStoreDelegCreds,
3980Sstevel@tonic-gate 	sGssUseSessionCredCache, sGssCleanupCreds,
3990Sstevel@tonic-gate #endif /* GSSAPI */
4000Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
4010Sstevel@tonic-gate 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
4020Sstevel@tonic-gate #endif
4030Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
4040Sstevel@tonic-gate 	sKerberosTgtPassing,
4050Sstevel@tonic-gate #endif
4060Sstevel@tonic-gate #ifdef AFS
4070Sstevel@tonic-gate 	sAFSTokenPassing,
4080Sstevel@tonic-gate #endif
4090Sstevel@tonic-gate 	sChallengeResponseAuthentication,
4100Sstevel@tonic-gate 	sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
4110Sstevel@tonic-gate 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
4120Sstevel@tonic-gate 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
4130Sstevel@tonic-gate 	sStrictModes, sEmptyPasswd, sKeepAlives,
4140Sstevel@tonic-gate 	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
4150Sstevel@tonic-gate 	sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
4160Sstevel@tonic-gate 	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
4170Sstevel@tonic-gate 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
4180Sstevel@tonic-gate 	sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
4190Sstevel@tonic-gate 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
4200Sstevel@tonic-gate 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
4210Sstevel@tonic-gate 	sMaxAuthTries, sMaxAuthTriesLog, sUsePrivilegeSeparation,
4229139SJan.Pechanec@Sun.COM 	sLookupClientHostnames, sUseOpenSSLEngine, sChrootDirectory,
42311044SHuie-Ying.Lee@Sun.COM 	sMatch,
4240Sstevel@tonic-gate 	sDeprecated
4250Sstevel@tonic-gate } ServerOpCodes;
4260Sstevel@tonic-gate 
42711044SHuie-Ying.Lee@Sun.COM #define SSHCFG_GLOBAL	0x01	/* allowed in main section of sshd_config */
42811044SHuie-Ying.Lee@Sun.COM #define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
42911044SHuie-Ying.Lee@Sun.COM #define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
43011044SHuie-Ying.Lee@Sun.COM 
4310Sstevel@tonic-gate /* Textual representation of the tokens. */
4320Sstevel@tonic-gate static struct {
4330Sstevel@tonic-gate 	const char *name;
4340Sstevel@tonic-gate 	ServerOpCodes opcode;
43511044SHuie-Ying.Lee@Sun.COM 	u_int flags;
4360Sstevel@tonic-gate } keywords[] = {
4370Sstevel@tonic-gate 	/* Portable-specific options */
43811044SHuie-Ying.Lee@Sun.COM 	{ "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt, SSHCFG_GLOBAL },
4390Sstevel@tonic-gate 	/* Standard Options */
44011044SHuie-Ying.Lee@Sun.COM 	{ "port", sPort, SSHCFG_GLOBAL },
44111044SHuie-Ying.Lee@Sun.COM 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
44211044SHuie-Ying.Lee@Sun.COM 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },			/* alias */
44311044SHuie-Ying.Lee@Sun.COM 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
44411044SHuie-Ying.Lee@Sun.COM 	{ "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
44511044SHuie-Ying.Lee@Sun.COM 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
44611044SHuie-Ying.Lee@Sun.COM 	{ "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
44711044SHuie-Ying.Lee@Sun.COM 	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
44811044SHuie-Ying.Lee@Sun.COM 	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
44911044SHuie-Ying.Lee@Sun.COM 	{ "loglevel", sLogLevel, SSHCFG_GLOBAL },
45011044SHuie-Ying.Lee@Sun.COM 	{ "rhostsauthentication", sRhostsAuthentication, SSHCFG_GLOBAL },
45111044SHuie-Ying.Lee@Sun.COM 	{ "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
45211044SHuie-Ying.Lee@Sun.COM 	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
4530Sstevel@tonic-gate 	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
45411044SHuie-Ying.Lee@Sun.COM 	{ "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
45511044SHuie-Ying.Lee@Sun.COM 	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
45611044SHuie-Ying.Lee@Sun.COM 	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL },	/* alias */
4570Sstevel@tonic-gate #ifdef GSSAPI
45811044SHuie-Ying.Lee@Sun.COM 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
45911044SHuie-Ying.Lee@Sun.COM 	{ "gssapikeyexchange", sGssKeyEx,   SSHCFG_GLOBAL },
46011044SHuie-Ying.Lee@Sun.COM 	{ "gssapistoredelegatedcredentials", sGssStoreDelegCreds, SSHCFG_GLOBAL },
46111044SHuie-Ying.Lee@Sun.COM 	{ "gssauthentication", sGssAuthentication, SSHCFG_GLOBAL },	/* alias */
46211044SHuie-Ying.Lee@Sun.COM 	{ "gsskeyex", sGssKeyEx, SSHCFG_GLOBAL },	/* alias */
46311044SHuie-Ying.Lee@Sun.COM 	{ "gssstoredelegcreds", sGssStoreDelegCreds, SSHCFG_GLOBAL },	/* alias */
4640Sstevel@tonic-gate #ifndef SUNW_GSSAPI
46511044SHuie-Ying.Lee@Sun.COM 	{ "gssusesessionccache", sGssUseSessionCredCache, SSHCFG_GLOBAL },
46611044SHuie-Ying.Lee@Sun.COM 	{ "gssusesessioncredcache", sGssUseSessionCredCache, SSHCFG_GLOBAL },
46711044SHuie-Ying.Lee@Sun.COM 	{ "gsscleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
4680Sstevel@tonic-gate #endif /* SUNW_GSSAPI */
4690Sstevel@tonic-gate #endif
4700Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
47111044SHuie-Ying.Lee@Sun.COM 	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
47211044SHuie-Ying.Lee@Sun.COM 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
47311044SHuie-Ying.Lee@Sun.COM 	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
4740Sstevel@tonic-gate #endif
4750Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
47611044SHuie-Ying.Lee@Sun.COM 	{ "kerberostgtpassing", sKerberosTgtPassing, SSHCFG_GLOBAL },
4770Sstevel@tonic-gate #endif
4780Sstevel@tonic-gate #ifdef AFS
47911044SHuie-Ying.Lee@Sun.COM 	{ "afstokenpassing", sAFSTokenPassing, SSHCFG_GLOBAL },
4800Sstevel@tonic-gate #endif
48111044SHuie-Ying.Lee@Sun.COM 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
48211044SHuie-Ying.Lee@Sun.COM 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
48311044SHuie-Ying.Lee@Sun.COM 	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
48411044SHuie-Ying.Lee@Sun.COM 	{ "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
48511044SHuie-Ying.Lee@Sun.COM 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
48611044SHuie-Ying.Lee@Sun.COM 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
48711044SHuie-Ying.Lee@Sun.COM 	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
48811044SHuie-Ying.Lee@Sun.COM 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
48911044SHuie-Ying.Lee@Sun.COM 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
49011044SHuie-Ying.Lee@Sun.COM 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
49111044SHuie-Ying.Lee@Sun.COM 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
49211044SHuie-Ying.Lee@Sun.COM 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
49311044SHuie-Ying.Lee@Sun.COM 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
49411044SHuie-Ying.Lee@Sun.COM 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
49511044SHuie-Ying.Lee@Sun.COM 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
49611044SHuie-Ying.Lee@Sun.COM 	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
49711044SHuie-Ying.Lee@Sun.COM 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
49811044SHuie-Ying.Lee@Sun.COM 	{ "uselogin", sUseLogin, SSHCFG_GLOBAL },
49911044SHuie-Ying.Lee@Sun.COM 	{ "compression", sCompression, SSHCFG_GLOBAL },
50011044SHuie-Ying.Lee@Sun.COM 	{ "keepalive", sKeepAlives, SSHCFG_GLOBAL },
50111044SHuie-Ying.Lee@Sun.COM 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
50211044SHuie-Ying.Lee@Sun.COM 	{ "allowusers", sAllowUsers, SSHCFG_GLOBAL },
50311044SHuie-Ying.Lee@Sun.COM 	{ "denyusers", sDenyUsers, SSHCFG_GLOBAL },
50411044SHuie-Ying.Lee@Sun.COM 	{ "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
50511044SHuie-Ying.Lee@Sun.COM 	{ "denygroups", sDenyGroups, SSHCFG_GLOBAL },
50611044SHuie-Ying.Lee@Sun.COM 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
50711044SHuie-Ying.Lee@Sun.COM 	{ "macs", sMacs, SSHCFG_GLOBAL},
50811044SHuie-Ying.Lee@Sun.COM 	{ "protocol", sProtocol,SSHCFG_GLOBAL },
50911044SHuie-Ying.Lee@Sun.COM 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
51011044SHuie-Ying.Lee@Sun.COM 	{ "subsystem", sSubsystem, SSHCFG_GLOBAL},
51111044SHuie-Ying.Lee@Sun.COM 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
51211044SHuie-Ying.Lee@Sun.COM 	{ "banner", sBanner, SSHCFG_ALL },
51311044SHuie-Ying.Lee@Sun.COM 	{ "verifyreversemapping", sVerifyReverseMapping, SSHCFG_GLOBAL },
51411044SHuie-Ying.Lee@Sun.COM 	{ "reversemappingcheck", sVerifyReverseMapping,SSHCFG_GLOBAL },
51511044SHuie-Ying.Lee@Sun.COM 	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
51611044SHuie-Ying.Lee@Sun.COM 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
51711044SHuie-Ying.Lee@Sun.COM 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
51811044SHuie-Ying.Lee@Sun.COM 	{ "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
51911044SHuie-Ying.Lee@Sun.COM 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
52011044SHuie-Ying.Lee@Sun.COM 	{ "maxauthtrieslog", sMaxAuthTriesLog, SSHCFG_GLOBAL },
52111044SHuie-Ying.Lee@Sun.COM 	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
52211044SHuie-Ying.Lee@Sun.COM 	{ "lookupclienthostnames", sLookupClientHostnames, SSHCFG_GLOBAL },
52311044SHuie-Ying.Lee@Sun.COM 	{ "useopensslengine", sUseOpenSSLEngine, SSHCFG_GLOBAL },
52411044SHuie-Ying.Lee@Sun.COM 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
52511044SHuie-Ying.Lee@Sun.COM 	{ "match", sMatch, SSHCFG_ALL },
52611044SHuie-Ying.Lee@Sun.COM 
52711044SHuie-Ying.Lee@Sun.COM 	{ NULL, sBadOption, 0 }
5280Sstevel@tonic-gate };
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate /*
5310Sstevel@tonic-gate  * Returns the number of the token pointed to by cp or sBadOption.
5320Sstevel@tonic-gate  */
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate static ServerOpCodes
5350Sstevel@tonic-gate parse_token(const char *cp, const char *filename,
53611044SHuie-Ying.Lee@Sun.COM 	    int linenum, u_int *flags)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	u_int i;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	for (i = 0; keywords[i].name; i++)
54111044SHuie-Ying.Lee@Sun.COM 		if (strcasecmp(cp, keywords[i].name) == 0) {
54211044SHuie-Ying.Lee@Sun.COM 			*flags = keywords[i].flags;
5430Sstevel@tonic-gate 			return keywords[i].opcode;
54411044SHuie-Ying.Lee@Sun.COM 		}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	error("%s: line %d: Bad configuration option: %s",
5470Sstevel@tonic-gate 	    filename, linenum, cp);
5480Sstevel@tonic-gate 	return sBadOption;
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate static void
5520Sstevel@tonic-gate add_listen_addr(ServerOptions *options, char *addr, u_short port)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	int i;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	if (options->num_ports == 0)
5570Sstevel@tonic-gate 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
5580Sstevel@tonic-gate 	if (port == 0)
5590Sstevel@tonic-gate 		for (i = 0; i < options->num_ports; i++)
5600Sstevel@tonic-gate 			add_one_listen_addr(options, addr, options->ports[i]);
5610Sstevel@tonic-gate 	else
5620Sstevel@tonic-gate 		add_one_listen_addr(options, addr, port);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate static void
5660Sstevel@tonic-gate add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	struct addrinfo hints, *ai, *aitop;
5690Sstevel@tonic-gate 	char strport[NI_MAXSERV];
5700Sstevel@tonic-gate 	int gaierr;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	(void) memset(&hints, 0, sizeof(hints));
5730Sstevel@tonic-gate 	hints.ai_family = IPv4or6;
5740Sstevel@tonic-gate 	hints.ai_socktype = SOCK_STREAM;
5750Sstevel@tonic-gate 	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
5760Sstevel@tonic-gate 	(void) snprintf(strport, sizeof strport, "%u", port);
5770Sstevel@tonic-gate 	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
5780Sstevel@tonic-gate 		fatal("bad addr or host: %s (%s)",
5790Sstevel@tonic-gate 		    addr ? addr : "<NULL>",
5800Sstevel@tonic-gate 		    gai_strerror(gaierr));
5810Sstevel@tonic-gate 	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
5820Sstevel@tonic-gate 		;
5830Sstevel@tonic-gate 	ai->ai_next = options->listen_addrs;
5840Sstevel@tonic-gate 	options->listen_addrs = aitop;
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate 
58711044SHuie-Ying.Lee@Sun.COM /*
58811044SHuie-Ying.Lee@Sun.COM  * The strategy for the Match blocks is that the config file is parsed twice.
58911044SHuie-Ying.Lee@Sun.COM  *
59011044SHuie-Ying.Lee@Sun.COM  * The first time is at startup.  activep is initialized to 1 and the
59111044SHuie-Ying.Lee@Sun.COM  * directives in the global context are processed and acted on.  Hitting a
59211044SHuie-Ying.Lee@Sun.COM  * Match directive unsets activep and the directives inside the block are
59311044SHuie-Ying.Lee@Sun.COM  * checked for syntax only.
59411044SHuie-Ying.Lee@Sun.COM  *
59511044SHuie-Ying.Lee@Sun.COM  * The second time is after a connection has been established but before
59611044SHuie-Ying.Lee@Sun.COM  * authentication.  activep is initialized to 2 and global config directives
59711044SHuie-Ying.Lee@Sun.COM  * are ignored since they have already been processed.  If the criteria in a
59811044SHuie-Ying.Lee@Sun.COM  * Match block is met, activep is set and the subsequent directives
59911044SHuie-Ying.Lee@Sun.COM  * processed and actioned until EOF or another Match block unsets it.  Any
60011044SHuie-Ying.Lee@Sun.COM  * options set are copied into the main server config.
60111044SHuie-Ying.Lee@Sun.COM  *
60211044SHuie-Ying.Lee@Sun.COM  * Potential additions/improvements:
60311044SHuie-Ying.Lee@Sun.COM  *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
60411044SHuie-Ying.Lee@Sun.COM  *
60511044SHuie-Ying.Lee@Sun.COM  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
60611044SHuie-Ying.Lee@Sun.COM  *	Match Address 192.168.0.*
60711044SHuie-Ying.Lee@Sun.COM  *		Tag trusted
60811044SHuie-Ying.Lee@Sun.COM  *	Match Group wheel
60911044SHuie-Ying.Lee@Sun.COM  *		Tag trusted
61011044SHuie-Ying.Lee@Sun.COM  *	Match Tag trusted
61111044SHuie-Ying.Lee@Sun.COM  *		AllowTcpForwarding yes
61211044SHuie-Ying.Lee@Sun.COM  *		GatewayPorts clientspecified
61311044SHuie-Ying.Lee@Sun.COM  *		[...]
61411044SHuie-Ying.Lee@Sun.COM  *
61511044SHuie-Ying.Lee@Sun.COM  *  - Add a PermittedChannelRequests directive
61611044SHuie-Ying.Lee@Sun.COM  *	Match Group shell
61711044SHuie-Ying.Lee@Sun.COM  *		PermittedChannelRequests session,forwarded-tcpip
61811044SHuie-Ying.Lee@Sun.COM  */
61911044SHuie-Ying.Lee@Sun.COM 
62011044SHuie-Ying.Lee@Sun.COM static int
62111044SHuie-Ying.Lee@Sun.COM match_cfg_line_group(const char *grps, int line, const char *user)
62211044SHuie-Ying.Lee@Sun.COM {
62311044SHuie-Ying.Lee@Sun.COM 	int result = 0;
62411044SHuie-Ying.Lee@Sun.COM 	struct passwd *pw;
62511044SHuie-Ying.Lee@Sun.COM 
62611044SHuie-Ying.Lee@Sun.COM 	if (user == NULL)
62711044SHuie-Ying.Lee@Sun.COM 		goto out;
62811044SHuie-Ying.Lee@Sun.COM 
62911044SHuie-Ying.Lee@Sun.COM 	if ((pw = getpwnam(user)) == NULL) {
63011044SHuie-Ying.Lee@Sun.COM 		debug("Can't match group at line %d because user %.100s does "
63111044SHuie-Ying.Lee@Sun.COM 		    "not exist", line, user);
63211044SHuie-Ying.Lee@Sun.COM 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
63311044SHuie-Ying.Lee@Sun.COM 		debug("Can't Match group because user %.100s not in any group "
63411044SHuie-Ying.Lee@Sun.COM 		    "at line %d", user, line);
63511044SHuie-Ying.Lee@Sun.COM 	} else if (ga_match_pattern_list(grps) != 1) {
63611044SHuie-Ying.Lee@Sun.COM 		debug("user %.100s does not match group list %.100s at line %d",
63711044SHuie-Ying.Lee@Sun.COM 		    user, grps, line);
63811044SHuie-Ying.Lee@Sun.COM 	} else {
63911044SHuie-Ying.Lee@Sun.COM 		debug("user %.100s matched group list %.100s at line %d", user,
64011044SHuie-Ying.Lee@Sun.COM 		    grps, line);
64111044SHuie-Ying.Lee@Sun.COM 		result = 1;
64211044SHuie-Ying.Lee@Sun.COM 	}
64311044SHuie-Ying.Lee@Sun.COM out:
64411044SHuie-Ying.Lee@Sun.COM 	ga_free();
64511044SHuie-Ying.Lee@Sun.COM 	return result;
64611044SHuie-Ying.Lee@Sun.COM }
64711044SHuie-Ying.Lee@Sun.COM 
64811044SHuie-Ying.Lee@Sun.COM static int
64911044SHuie-Ying.Lee@Sun.COM match_cfg_line(char **condition, int line, const char *user, const char *host,
65011044SHuie-Ying.Lee@Sun.COM     const char *address)
65111044SHuie-Ying.Lee@Sun.COM {
65211044SHuie-Ying.Lee@Sun.COM 	int result = 1;
65311044SHuie-Ying.Lee@Sun.COM 	char *arg, *attrib, *cp = *condition;
65411044SHuie-Ying.Lee@Sun.COM 	size_t len;
65511044SHuie-Ying.Lee@Sun.COM 
65611044SHuie-Ying.Lee@Sun.COM 	if (user == NULL)
65711044SHuie-Ying.Lee@Sun.COM 		debug3("checking syntax for 'Match %s'", cp);
65811044SHuie-Ying.Lee@Sun.COM 	else
65911044SHuie-Ying.Lee@Sun.COM 		debug3("checking match for '%s' user %s host %s addr %s", cp,
66011044SHuie-Ying.Lee@Sun.COM 		    user ? user : "(null)", host ? host : "(null)",
66111044SHuie-Ying.Lee@Sun.COM 		    address ? address : "(null)");
66211044SHuie-Ying.Lee@Sun.COM 
663*11060SHuie-Ying.Lee@Sun.COM 	while ((attrib = strdelim(&cp)) != NULL && *attrib != '\0') {
66411044SHuie-Ying.Lee@Sun.COM 		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
66511044SHuie-Ying.Lee@Sun.COM 			error("Missing Match criteria for %s", attrib);
66611044SHuie-Ying.Lee@Sun.COM 			return -1;
66711044SHuie-Ying.Lee@Sun.COM 		}
66811044SHuie-Ying.Lee@Sun.COM 		len = strlen(arg);
66911044SHuie-Ying.Lee@Sun.COM 		if (strcasecmp(attrib, "user") == 0) {
67011044SHuie-Ying.Lee@Sun.COM 			if (!user) {
67111044SHuie-Ying.Lee@Sun.COM 				result = 0;
67211044SHuie-Ying.Lee@Sun.COM 				continue;
67311044SHuie-Ying.Lee@Sun.COM 			}
67411044SHuie-Ying.Lee@Sun.COM 			if (match_pattern_list(user, arg, len, 0) != 1)
67511044SHuie-Ying.Lee@Sun.COM 				result = 0;
67611044SHuie-Ying.Lee@Sun.COM 			else
67711044SHuie-Ying.Lee@Sun.COM 				debug("user %.100s matched 'User %.100s' at "
67811044SHuie-Ying.Lee@Sun.COM 				    "line %d", user, arg, line);
67911044SHuie-Ying.Lee@Sun.COM 		} else if (strcasecmp(attrib, "group") == 0) {
68011044SHuie-Ying.Lee@Sun.COM 			switch (match_cfg_line_group(arg, line, user)) {
68111044SHuie-Ying.Lee@Sun.COM 			case -1:
68211044SHuie-Ying.Lee@Sun.COM 				return -1;
68311044SHuie-Ying.Lee@Sun.COM 			case 0:
68411044SHuie-Ying.Lee@Sun.COM 				result = 0;
68511044SHuie-Ying.Lee@Sun.COM 			}
68611044SHuie-Ying.Lee@Sun.COM 		} else if (strcasecmp(attrib, "host") == 0) {
68711044SHuie-Ying.Lee@Sun.COM 			if (!host) {
68811044SHuie-Ying.Lee@Sun.COM 				result = 0;
68911044SHuie-Ying.Lee@Sun.COM 				continue;
69011044SHuie-Ying.Lee@Sun.COM 			}
69111044SHuie-Ying.Lee@Sun.COM 			if (match_hostname(host, arg, len) != 1)
69211044SHuie-Ying.Lee@Sun.COM 				result = 0;
69311044SHuie-Ying.Lee@Sun.COM 			else
69411044SHuie-Ying.Lee@Sun.COM 				debug("connection from %.100s matched 'Host "
69511044SHuie-Ying.Lee@Sun.COM 				    "%.100s' at line %d", host, arg, line);
69611044SHuie-Ying.Lee@Sun.COM 		} else if (strcasecmp(attrib, "address") == 0) {
69711044SHuie-Ying.Lee@Sun.COM 			switch (addr_match_list(address, arg)) {
69811044SHuie-Ying.Lee@Sun.COM 			case 1:
69911044SHuie-Ying.Lee@Sun.COM 				debug("connection from %.100s matched 'Address "
70011044SHuie-Ying.Lee@Sun.COM 				    "%.100s' at line %d", address, arg, line);
70111044SHuie-Ying.Lee@Sun.COM 				break;
70211044SHuie-Ying.Lee@Sun.COM 			case 0:
70311044SHuie-Ying.Lee@Sun.COM 			case -1:
70411044SHuie-Ying.Lee@Sun.COM 				result = 0;
70511044SHuie-Ying.Lee@Sun.COM 				break;
70611044SHuie-Ying.Lee@Sun.COM 			case -2:
70711044SHuie-Ying.Lee@Sun.COM 				return -1;
70811044SHuie-Ying.Lee@Sun.COM 			}
70911044SHuie-Ying.Lee@Sun.COM 		} else {
71011044SHuie-Ying.Lee@Sun.COM 			error("Unsupported Match attribute %s", attrib);
71111044SHuie-Ying.Lee@Sun.COM 			return -1;
71211044SHuie-Ying.Lee@Sun.COM 		}
71311044SHuie-Ying.Lee@Sun.COM 	}
71411044SHuie-Ying.Lee@Sun.COM 	if (user != NULL)
71511044SHuie-Ying.Lee@Sun.COM 		debug3("match %sfound", result ? "" : "not ");
71611044SHuie-Ying.Lee@Sun.COM 	*condition = cp;
71711044SHuie-Ying.Lee@Sun.COM 	return result;
71811044SHuie-Ying.Lee@Sun.COM }
71911044SHuie-Ying.Lee@Sun.COM 
72011044SHuie-Ying.Lee@Sun.COM #define WHITESPACE " \t\r\n"
72111044SHuie-Ying.Lee@Sun.COM 
7220Sstevel@tonic-gate int
7230Sstevel@tonic-gate process_server_config_line(ServerOptions *options, char *line,
72411044SHuie-Ying.Lee@Sun.COM     const char *filename, int linenum, int *activep, const char *user,
72511044SHuie-Ying.Lee@Sun.COM     const char *host, const char *address)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate 	char *cp, **charptr, *arg, *p;
72811044SHuie-Ying.Lee@Sun.COM 	int cmdline = 0, *intptr, value, n;
7290Sstevel@tonic-gate 	ServerOpCodes opcode;
73011044SHuie-Ying.Lee@Sun.COM 	u_int i, flags = 0;
7319139SJan.Pechanec@Sun.COM 	size_t len;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	cp = line;
7340Sstevel@tonic-gate 	arg = strdelim(&cp);
7350Sstevel@tonic-gate 	/* Ignore leading whitespace */
7360Sstevel@tonic-gate 	if (*arg == '\0')
7370Sstevel@tonic-gate 		arg = strdelim(&cp);
7380Sstevel@tonic-gate 	if (!arg || !*arg || *arg == '#')
7390Sstevel@tonic-gate 		return 0;
7400Sstevel@tonic-gate 	intptr = NULL;
7410Sstevel@tonic-gate 	charptr = NULL;
74211044SHuie-Ying.Lee@Sun.COM 	opcode = parse_token(arg, filename, linenum, &flags);
74311044SHuie-Ying.Lee@Sun.COM 
74411044SHuie-Ying.Lee@Sun.COM 	if (activep == NULL) { /* We are processing a command line directive */
74511044SHuie-Ying.Lee@Sun.COM 		cmdline = 1;
74611044SHuie-Ying.Lee@Sun.COM 		activep = &cmdline;
74711044SHuie-Ying.Lee@Sun.COM 	}
74811044SHuie-Ying.Lee@Sun.COM 	if (*activep && opcode != sMatch)
74911044SHuie-Ying.Lee@Sun.COM 		debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
75011044SHuie-Ying.Lee@Sun.COM 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
75111044SHuie-Ying.Lee@Sun.COM 		if (user == NULL) {
75211044SHuie-Ying.Lee@Sun.COM 			fatal("%s line %d: Directive '%s' is not allowed "
75311044SHuie-Ying.Lee@Sun.COM 			    "within a Match block", filename, linenum, arg);
75411044SHuie-Ying.Lee@Sun.COM 		} else { /* this is a directive we have already processed */
75511044SHuie-Ying.Lee@Sun.COM 			while (arg)
75611044SHuie-Ying.Lee@Sun.COM 				arg = strdelim(&cp);
75711044SHuie-Ying.Lee@Sun.COM 			return 0;
75811044SHuie-Ying.Lee@Sun.COM 		}
75911044SHuie-Ying.Lee@Sun.COM 	}
76011044SHuie-Ying.Lee@Sun.COM 
7610Sstevel@tonic-gate 	switch (opcode) {
7620Sstevel@tonic-gate 	/* Portable-specific options */
7630Sstevel@tonic-gate 	case sPAMAuthenticationViaKbdInt:
7640Sstevel@tonic-gate 		intptr = &options->pam_authentication_via_kbd_int;
7650Sstevel@tonic-gate 		goto parse_flag;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/* Standard Options */
7680Sstevel@tonic-gate 	case sBadOption:
7690Sstevel@tonic-gate 		return -1;
7700Sstevel@tonic-gate 	case sPort:
7710Sstevel@tonic-gate 		/* ignore ports from configfile if cmdline specifies ports */
7720Sstevel@tonic-gate 		if (options->ports_from_cmdline)
7730Sstevel@tonic-gate 			return 0;
7740Sstevel@tonic-gate 		if (options->listen_addrs != NULL)
7750Sstevel@tonic-gate 			fatal("%s line %d: ports must be specified before "
7760Sstevel@tonic-gate 			    "ListenAddress.", filename, linenum);
7770Sstevel@tonic-gate 		if (options->num_ports >= MAX_PORTS)
7780Sstevel@tonic-gate 			fatal("%s line %d: too many ports.",
7790Sstevel@tonic-gate 			    filename, linenum);
7800Sstevel@tonic-gate 		arg = strdelim(&cp);
7810Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7820Sstevel@tonic-gate 			fatal("%s line %d: missing port number.",
7830Sstevel@tonic-gate 			    filename, linenum);
7840Sstevel@tonic-gate 		options->ports[options->num_ports++] = a2port(arg);
7850Sstevel@tonic-gate 		if (options->ports[options->num_ports-1] == 0)
7860Sstevel@tonic-gate 			fatal("%s line %d: Badly formatted port number.",
7870Sstevel@tonic-gate 			    filename, linenum);
7880Sstevel@tonic-gate 		break;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	case sServerKeyBits:
7910Sstevel@tonic-gate 		intptr = &options->server_key_bits;
7920Sstevel@tonic-gate parse_int:
7930Sstevel@tonic-gate 		arg = strdelim(&cp);
7940Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7950Sstevel@tonic-gate 			fatal("%s line %d: missing integer value.",
7960Sstevel@tonic-gate 			    filename, linenum);
7970Sstevel@tonic-gate 		value = atoi(arg);
79811044SHuie-Ying.Lee@Sun.COM 		if (*activep && *intptr == -1)
7990Sstevel@tonic-gate 			*intptr = value;
8000Sstevel@tonic-gate 		break;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	case sLoginGraceTime:
8030Sstevel@tonic-gate 		intptr = &options->login_grace_time;
8040Sstevel@tonic-gate parse_time:
8050Sstevel@tonic-gate 		arg = strdelim(&cp);
8060Sstevel@tonic-gate 		if (!arg || *arg == '\0')
8070Sstevel@tonic-gate 			fatal("%s line %d: missing time value.",
8080Sstevel@tonic-gate 			    filename, linenum);
8090Sstevel@tonic-gate 		if ((value = convtime(arg)) == -1)
8100Sstevel@tonic-gate 			fatal("%s line %d: invalid time value.",
8110Sstevel@tonic-gate 			    filename, linenum);
8120Sstevel@tonic-gate 		if (*intptr == -1)
8130Sstevel@tonic-gate 			*intptr = value;
8140Sstevel@tonic-gate 		break;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	case sKeyRegenerationTime:
8170Sstevel@tonic-gate 		intptr = &options->key_regeneration_time;
8180Sstevel@tonic-gate 		goto parse_time;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	case sListenAddress:
8210Sstevel@tonic-gate 		arg = strdelim(&cp);
8220Sstevel@tonic-gate 		if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
8230Sstevel@tonic-gate 			fatal("%s line %d: missing inet addr.",
8240Sstevel@tonic-gate 			    filename, linenum);
8250Sstevel@tonic-gate 		if (*arg == '[') {
8260Sstevel@tonic-gate 			if ((p = strchr(arg, ']')) == NULL)
8270Sstevel@tonic-gate 				fatal("%s line %d: bad ipv6 inet addr usage.",
8280Sstevel@tonic-gate 				    filename, linenum);
8290Sstevel@tonic-gate 			arg++;
8300Sstevel@tonic-gate 			(void) memmove(p, p+1, strlen(p+1)+1);
8310Sstevel@tonic-gate 		} else if (((p = strchr(arg, ':')) == NULL) ||
8320Sstevel@tonic-gate 			    (strchr(p+1, ':') != NULL)) {
8330Sstevel@tonic-gate 			add_listen_addr(options, arg, 0);
8340Sstevel@tonic-gate 			break;
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 		if (*p == ':') {
8370Sstevel@tonic-gate 			u_short port;
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 			p++;
8400Sstevel@tonic-gate 			if (*p == '\0')
8410Sstevel@tonic-gate 				fatal("%s line %d: bad inet addr:port usage.",
8420Sstevel@tonic-gate 				    filename, linenum);
8430Sstevel@tonic-gate 			else {
8440Sstevel@tonic-gate 				*(p-1) = '\0';
8450Sstevel@tonic-gate 				if ((port = a2port(p)) == 0)
8460Sstevel@tonic-gate 					fatal("%s line %d: bad port number.",
8470Sstevel@tonic-gate 					    filename, linenum);
8480Sstevel@tonic-gate 				add_listen_addr(options, arg, port);
8490Sstevel@tonic-gate 			}
8500Sstevel@tonic-gate 		} else if (*p == '\0')
8510Sstevel@tonic-gate 			add_listen_addr(options, arg, 0);
8520Sstevel@tonic-gate 		else
8530Sstevel@tonic-gate 			fatal("%s line %d: bad inet addr usage.",
8540Sstevel@tonic-gate 			    filename, linenum);
8550Sstevel@tonic-gate 		break;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	case sHostKeyFile:
8580Sstevel@tonic-gate 		intptr = &options->num_host_key_files;
8590Sstevel@tonic-gate 		if (*intptr >= MAX_HOSTKEYS)
8600Sstevel@tonic-gate 			fatal("%s line %d: too many host keys specified (max %d).",
8610Sstevel@tonic-gate 			    filename, linenum, MAX_HOSTKEYS);
8620Sstevel@tonic-gate 		charptr = &options->host_key_files[*intptr];
8630Sstevel@tonic-gate parse_filename:
8640Sstevel@tonic-gate 		arg = strdelim(&cp);
8650Sstevel@tonic-gate 		if (!arg || *arg == '\0')
8660Sstevel@tonic-gate 			fatal("%s line %d: missing file name.",
8670Sstevel@tonic-gate 			    filename, linenum);
86811044SHuie-Ying.Lee@Sun.COM 		if (*activep && *charptr == NULL) {
8690Sstevel@tonic-gate 			*charptr = tilde_expand_filename(arg, getuid());
8700Sstevel@tonic-gate 			/* increase optional counter */
8710Sstevel@tonic-gate 			if (intptr != NULL)
8720Sstevel@tonic-gate 				*intptr = *intptr + 1;
8730Sstevel@tonic-gate 		}
8740Sstevel@tonic-gate 		break;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	case sPidFile:
8770Sstevel@tonic-gate 		charptr = &options->pid_file;
8780Sstevel@tonic-gate 		goto parse_filename;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	case sPermitRootLogin:
8810Sstevel@tonic-gate 		intptr = &options->permit_root_login;
8820Sstevel@tonic-gate 		arg = strdelim(&cp);
8830Sstevel@tonic-gate 		if (!arg || *arg == '\0')
8840Sstevel@tonic-gate 			fatal("%s line %d: missing yes/"
8850Sstevel@tonic-gate 			    "without-password/forced-commands-only/no "
8860Sstevel@tonic-gate 			    "argument.", filename, linenum);
8870Sstevel@tonic-gate 		value = 0;	/* silence compiler */
8880Sstevel@tonic-gate 		if (strcmp(arg, "without-password") == 0)
8890Sstevel@tonic-gate 			value = PERMIT_NO_PASSWD;
8900Sstevel@tonic-gate 		else if (strcmp(arg, "forced-commands-only") == 0)
8910Sstevel@tonic-gate 			value = PERMIT_FORCED_ONLY;
8920Sstevel@tonic-gate 		else if (strcmp(arg, "yes") == 0)
8930Sstevel@tonic-gate 			value = PERMIT_YES;
8940Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0)
8950Sstevel@tonic-gate 			value = PERMIT_NO;
8960Sstevel@tonic-gate 		else
8970Sstevel@tonic-gate 			fatal("%s line %d: Bad yes/"
8980Sstevel@tonic-gate 			    "without-password/forced-commands-only/no "
8990Sstevel@tonic-gate 			    "argument: %s", filename, linenum, arg);
90011044SHuie-Ying.Lee@Sun.COM 		if (*activep && *intptr == -1)
9010Sstevel@tonic-gate 			*intptr = value;
9020Sstevel@tonic-gate 		break;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	case sIgnoreRhosts:
9050Sstevel@tonic-gate 		intptr = &options->ignore_rhosts;
9060Sstevel@tonic-gate parse_flag:
9070Sstevel@tonic-gate 		arg = strdelim(&cp);
9080Sstevel@tonic-gate 		if (!arg || *arg == '\0')
9090Sstevel@tonic-gate 			fatal("%s line %d: missing yes/no argument.",
9100Sstevel@tonic-gate 			    filename, linenum);
9110Sstevel@tonic-gate 		value = 0;	/* silence compiler */
9120Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0)
9130Sstevel@tonic-gate 			value = 1;
9140Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0)
9150Sstevel@tonic-gate 			value = 0;
9160Sstevel@tonic-gate 		else
9170Sstevel@tonic-gate 			fatal("%s line %d: Bad yes/no argument: %s",
9180Sstevel@tonic-gate 				filename, linenum, arg);
91911044SHuie-Ying.Lee@Sun.COM 		if (*activep && *intptr == -1)
9200Sstevel@tonic-gate 			*intptr = value;
9210Sstevel@tonic-gate 		break;
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	case sIgnoreUserKnownHosts:
9240Sstevel@tonic-gate 		intptr = &options->ignore_user_known_hosts;
9250Sstevel@tonic-gate 		goto parse_flag;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	case sRhostsAuthentication:
9280Sstevel@tonic-gate 		intptr = &options->rhosts_authentication;
9290Sstevel@tonic-gate 		goto parse_flag;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	case sRhostsRSAAuthentication:
9320Sstevel@tonic-gate 		intptr = &options->rhosts_rsa_authentication;
9330Sstevel@tonic-gate 		goto parse_flag;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	case sHostbasedAuthentication:
9360Sstevel@tonic-gate 		intptr = &options->hostbased_authentication;
9370Sstevel@tonic-gate 		goto parse_flag;
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	case sHostbasedUsesNameFromPacketOnly:
9400Sstevel@tonic-gate 		intptr = &options->hostbased_uses_name_from_packet_only;
9410Sstevel@tonic-gate 		goto parse_flag;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	case sRSAAuthentication:
9440Sstevel@tonic-gate 		intptr = &options->rsa_authentication;
9450Sstevel@tonic-gate 		goto parse_flag;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	case sPubkeyAuthentication:
9480Sstevel@tonic-gate 		intptr = &options->pubkey_authentication;
9490Sstevel@tonic-gate 		goto parse_flag;
9500Sstevel@tonic-gate #ifdef GSSAPI
9510Sstevel@tonic-gate 	case sGssAuthentication:
9520Sstevel@tonic-gate 		intptr = &options->gss_authentication;
9530Sstevel@tonic-gate 		goto parse_flag;
9540Sstevel@tonic-gate 	case sGssKeyEx:
9550Sstevel@tonic-gate 		intptr = &options->gss_keyex;
9560Sstevel@tonic-gate 		goto parse_flag;
9570Sstevel@tonic-gate 	case sGssStoreDelegCreds:
9580Sstevel@tonic-gate 		intptr = &options->gss_keyex;
9590Sstevel@tonic-gate 		goto parse_flag;
9600Sstevel@tonic-gate #ifndef SUNW_GSSAPI
9610Sstevel@tonic-gate 	case sGssUseSessionCredCache:
9620Sstevel@tonic-gate 		intptr = &options->gss_use_session_ccache;
9630Sstevel@tonic-gate 		goto parse_flag;
9640Sstevel@tonic-gate 	case sGssCleanupCreds:
9650Sstevel@tonic-gate 		intptr = &options->gss_cleanup_creds;
9660Sstevel@tonic-gate 		goto parse_flag;
9670Sstevel@tonic-gate #endif /* SUNW_GSSAPI */
9680Sstevel@tonic-gate #endif /* GSSAPI */
9690Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
9700Sstevel@tonic-gate 	case sKerberosAuthentication:
9710Sstevel@tonic-gate 		intptr = &options->kerberos_authentication;
9720Sstevel@tonic-gate 		goto parse_flag;
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	case sKerberosOrLocalPasswd:
9750Sstevel@tonic-gate 		intptr = &options->kerberos_or_local_passwd;
9760Sstevel@tonic-gate 		goto parse_flag;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	case sKerberosTicketCleanup:
9790Sstevel@tonic-gate 		intptr = &options->kerberos_ticket_cleanup;
9800Sstevel@tonic-gate 		goto parse_flag;
9810Sstevel@tonic-gate #endif
9820Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
9830Sstevel@tonic-gate 	case sKerberosTgtPassing:
9840Sstevel@tonic-gate 		intptr = &options->kerberos_tgt_passing;
9850Sstevel@tonic-gate 		goto parse_flag;
9860Sstevel@tonic-gate #endif
9870Sstevel@tonic-gate #ifdef AFS
9880Sstevel@tonic-gate 	case sAFSTokenPassing:
9890Sstevel@tonic-gate 		intptr = &options->afs_token_passing;
9900Sstevel@tonic-gate 		goto parse_flag;
9910Sstevel@tonic-gate #endif
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	case sPasswordAuthentication:
9940Sstevel@tonic-gate 		intptr = &options->password_authentication;
9950Sstevel@tonic-gate 		goto parse_flag;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	case sKbdInteractiveAuthentication:
9980Sstevel@tonic-gate 		intptr = &options->kbd_interactive_authentication;
9990Sstevel@tonic-gate 		goto parse_flag;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	case sChallengeResponseAuthentication:
10020Sstevel@tonic-gate 		intptr = &options->challenge_response_authentication;
10030Sstevel@tonic-gate 		goto parse_flag;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	case sPrintMotd:
10060Sstevel@tonic-gate 		intptr = &options->print_motd;
10070Sstevel@tonic-gate 		goto parse_flag;
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	case sPrintLastLog:
10100Sstevel@tonic-gate 		intptr = &options->print_lastlog;
10110Sstevel@tonic-gate 		goto parse_flag;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	case sX11Forwarding:
10140Sstevel@tonic-gate 		intptr = &options->x11_forwarding;
10150Sstevel@tonic-gate 		goto parse_flag;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	case sX11DisplayOffset:
10180Sstevel@tonic-gate 		intptr = &options->x11_display_offset;
10190Sstevel@tonic-gate 		goto parse_int;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	case sX11UseLocalhost:
10220Sstevel@tonic-gate 		intptr = &options->x11_use_localhost;
10230Sstevel@tonic-gate 		goto parse_flag;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	case sXAuthLocation:
10260Sstevel@tonic-gate 		charptr = &options->xauth_location;
10270Sstevel@tonic-gate 		goto parse_filename;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	case sStrictModes:
10300Sstevel@tonic-gate 		intptr = &options->strict_modes;
10310Sstevel@tonic-gate 		goto parse_flag;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	case sKeepAlives:
10340Sstevel@tonic-gate 		intptr = &options->keepalives;
10350Sstevel@tonic-gate 		goto parse_flag;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	case sEmptyPasswd:
10380Sstevel@tonic-gate 		intptr = &options->permit_empty_passwd;
10390Sstevel@tonic-gate 		goto parse_flag;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	case sPermitUserEnvironment:
10420Sstevel@tonic-gate 		intptr = &options->permit_user_env;
10430Sstevel@tonic-gate 		goto parse_flag;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	case sUseLogin:
10469845SJan.Pechanec@Sun.COM 		log("%s line %d: ignoring UseLogin option value."
10479845SJan.Pechanec@Sun.COM 		    " This option is always off.", filename, linenum);
10489845SJan.Pechanec@Sun.COM 		while (arg)
10499845SJan.Pechanec@Sun.COM 			arg = strdelim(&cp);
10509845SJan.Pechanec@Sun.COM 		break;
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	case sCompression:
10530Sstevel@tonic-gate 		intptr = &options->compression;
10540Sstevel@tonic-gate 		goto parse_flag;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	case sGatewayPorts:
105711044SHuie-Ying.Lee@Sun.COM 		intptr = &options->gateway_ports;
10585334Sjp161948 		arg = strdelim(&cp);
105911044SHuie-Ying.Lee@Sun.COM 		if (!arg || *arg == '\0')
106011044SHuie-Ying.Lee@Sun.COM 			fatal("%s line %d: missing yes/no/clientspecified "
106111044SHuie-Ying.Lee@Sun.COM 			    "argument.", filename, linenum);
106211044SHuie-Ying.Lee@Sun.COM 		value = 0;	/* silence compiler */
10635334Sjp161948 		if (strcmp(arg, "clientspecified") == 0)
106411044SHuie-Ying.Lee@Sun.COM 			value = 2;
106511044SHuie-Ying.Lee@Sun.COM 		else if (strcmp(arg, "yes") == 0)
106611044SHuie-Ying.Lee@Sun.COM 			value = 1;
106711044SHuie-Ying.Lee@Sun.COM 		else if (strcmp(arg, "no") == 0)
106811044SHuie-Ying.Lee@Sun.COM 			value = 0;
10695334Sjp161948 		else
107011044SHuie-Ying.Lee@Sun.COM 			fatal("%s line %d: Bad yes/no/clientspecified "
107111044SHuie-Ying.Lee@Sun.COM 			    "argument: %s", filename, linenum, arg);
107211044SHuie-Ying.Lee@Sun.COM 		if (*activep && *intptr == -1)
107311044SHuie-Ying.Lee@Sun.COM 			*intptr = value;
10745334Sjp161948 		break;
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	case sVerifyReverseMapping:
10770Sstevel@tonic-gate 		intptr = &options->verify_reverse_mapping;
10780Sstevel@tonic-gate 		goto parse_flag;
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	case sLogFacility:
10810Sstevel@tonic-gate 		intptr = (int *) &options->log_facility;
10820Sstevel@tonic-gate 		arg = strdelim(&cp);
10830Sstevel@tonic-gate 		value = log_facility_number(arg);
10840Sstevel@tonic-gate 		if (value == SYSLOG_FACILITY_NOT_SET)
10850Sstevel@tonic-gate 			fatal("%.200s line %d: unsupported log facility '%s'",
10860Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
10870Sstevel@tonic-gate 		if (*intptr == -1)
10880Sstevel@tonic-gate 			*intptr = (SyslogFacility) value;
10890Sstevel@tonic-gate 		break;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	case sLogLevel:
10920Sstevel@tonic-gate 		intptr = (int *) &options->log_level;
10930Sstevel@tonic-gate 		arg = strdelim(&cp);
10940Sstevel@tonic-gate 		value = log_level_number(arg);
10950Sstevel@tonic-gate 		if (value == SYSLOG_LEVEL_NOT_SET)
10960Sstevel@tonic-gate 			fatal("%.200s line %d: unsupported log level '%s'",
10970Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
10980Sstevel@tonic-gate 		if (*intptr == -1)
10990Sstevel@tonic-gate 			*intptr = (LogLevel) value;
11000Sstevel@tonic-gate 		break;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	case sAllowTcpForwarding:
11030Sstevel@tonic-gate 		intptr = &options->allow_tcp_forwarding;
11040Sstevel@tonic-gate 		goto parse_flag;
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	case sUsePrivilegeSeparation:
11075562Sjp161948 		log("%s line %d: ignoring UsePrivilegeSeparation option value."
11085562Sjp161948 		    " This option is always on.", filename, linenum);
11095562Sjp161948 		while (arg)
11109845SJan.Pechanec@Sun.COM 			arg = strdelim(&cp);
11115562Sjp161948 		break;
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	case sAllowUsers:
11140Sstevel@tonic-gate 		while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
11150Sstevel@tonic-gate 			if (options->num_allow_users >= MAX_ALLOW_USERS)
11160Sstevel@tonic-gate 				fatal("%s line %d: too many allow users.",
11170Sstevel@tonic-gate 				    filename, linenum);
11180Sstevel@tonic-gate 			options->allow_users[options->num_allow_users++] =
11190Sstevel@tonic-gate 			    xstrdup(arg);
11200Sstevel@tonic-gate 		}
11210Sstevel@tonic-gate 		break;
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	case sDenyUsers:
11240Sstevel@tonic-gate 		while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
11250Sstevel@tonic-gate 			if (options->num_deny_users >= MAX_DENY_USERS)
11260Sstevel@tonic-gate 				fatal( "%s line %d: too many deny users.",
11270Sstevel@tonic-gate 				    filename, linenum);
11280Sstevel@tonic-gate 			options->deny_users[options->num_deny_users++] =
11290Sstevel@tonic-gate 			    xstrdup(arg);
11300Sstevel@tonic-gate 		}
11310Sstevel@tonic-gate 		break;
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	case sAllowGroups:
11340Sstevel@tonic-gate 		while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
11350Sstevel@tonic-gate 			if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
11360Sstevel@tonic-gate 				fatal("%s line %d: too many allow groups.",
11370Sstevel@tonic-gate 				    filename, linenum);
11380Sstevel@tonic-gate 			options->allow_groups[options->num_allow_groups++] =
11390Sstevel@tonic-gate 			    xstrdup(arg);
11400Sstevel@tonic-gate 		}
11410Sstevel@tonic-gate 		break;
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	case sDenyGroups:
11440Sstevel@tonic-gate 		while (((arg = strdelim(&cp)) != NULL) && *arg != '\0') {
11450Sstevel@tonic-gate 			if (options->num_deny_groups >= MAX_DENY_GROUPS)
11460Sstevel@tonic-gate 				fatal("%s line %d: too many deny groups.",
11470Sstevel@tonic-gate 				    filename, linenum);
11480Sstevel@tonic-gate 			options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
11490Sstevel@tonic-gate 		}
11500Sstevel@tonic-gate 		break;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	case sCiphers:
11530Sstevel@tonic-gate 		arg = strdelim(&cp);
11540Sstevel@tonic-gate 		if (!arg || *arg == '\0')
11550Sstevel@tonic-gate 			fatal("%s line %d: Missing argument.", filename, linenum);
11560Sstevel@tonic-gate 		if (!ciphers_valid(arg))
11570Sstevel@tonic-gate 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
11580Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
11590Sstevel@tonic-gate 		if (options->ciphers == NULL)
11600Sstevel@tonic-gate 			options->ciphers = xstrdup(arg);
11610Sstevel@tonic-gate 		break;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	case sMacs:
11640Sstevel@tonic-gate 		arg = strdelim(&cp);
11650Sstevel@tonic-gate 		if (!arg || *arg == '\0')
11660Sstevel@tonic-gate 			fatal("%s line %d: Missing argument.", filename, linenum);
11670Sstevel@tonic-gate 		if (!mac_valid(arg))
11680Sstevel@tonic-gate 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
11690Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
11700Sstevel@tonic-gate 		if (options->macs == NULL)
11710Sstevel@tonic-gate 			options->macs = xstrdup(arg);
11720Sstevel@tonic-gate 		break;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	case sProtocol:
11750Sstevel@tonic-gate 		intptr = &options->protocol;
11760Sstevel@tonic-gate 		arg = strdelim(&cp);
11770Sstevel@tonic-gate 		if (!arg || *arg == '\0')
11780Sstevel@tonic-gate 			fatal("%s line %d: Missing argument.", filename, linenum);
11790Sstevel@tonic-gate 		value = proto_spec(arg);
11800Sstevel@tonic-gate 		if (value == SSH_PROTO_UNKNOWN)
11810Sstevel@tonic-gate 			fatal("%s line %d: Bad protocol spec '%s'.",
11820Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
11830Sstevel@tonic-gate 		if (*intptr == SSH_PROTO_UNKNOWN)
11840Sstevel@tonic-gate 			*intptr = value;
11850Sstevel@tonic-gate 		break;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	case sSubsystem:
11880Sstevel@tonic-gate 		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
11890Sstevel@tonic-gate 			fatal("%s line %d: too many subsystems defined.",
11900Sstevel@tonic-gate 			    filename, linenum);
11910Sstevel@tonic-gate 		}
11920Sstevel@tonic-gate 		arg = strdelim(&cp);
11930Sstevel@tonic-gate 		if (!arg || *arg == '\0')
11940Sstevel@tonic-gate 			fatal("%s line %d: Missing subsystem name.",
11950Sstevel@tonic-gate 			    filename, linenum);
119611044SHuie-Ying.Lee@Sun.COM 		if (!*activep) {
119711044SHuie-Ying.Lee@Sun.COM 			arg = strdelim(&cp);
119811044SHuie-Ying.Lee@Sun.COM 			break;
119911044SHuie-Ying.Lee@Sun.COM 		}
12000Sstevel@tonic-gate 		for (i = 0; i < options->num_subsystems; i++)
12010Sstevel@tonic-gate 			if (strcmp(arg, options->subsystem_name[i]) == 0)
12020Sstevel@tonic-gate 				fatal("%s line %d: Subsystem '%s' already defined.",
12030Sstevel@tonic-gate 				    filename, linenum, arg);
12040Sstevel@tonic-gate 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
12050Sstevel@tonic-gate 		arg = strdelim(&cp);
12060Sstevel@tonic-gate 		if (!arg || *arg == '\0')
12070Sstevel@tonic-gate 			fatal("%s line %d: Missing subsystem command.",
12080Sstevel@tonic-gate 			    filename, linenum);
12090Sstevel@tonic-gate 		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
12109139SJan.Pechanec@Sun.COM 
12119139SJan.Pechanec@Sun.COM 		/*
12129139SJan.Pechanec@Sun.COM 		 * Collect arguments (separate to executable), including the
12139139SJan.Pechanec@Sun.COM 		 * name of the executable, in a way that is easier to parse
12149139SJan.Pechanec@Sun.COM 		 * later.
12159139SJan.Pechanec@Sun.COM 		 */
12169139SJan.Pechanec@Sun.COM 		p = xstrdup(arg);
12179139SJan.Pechanec@Sun.COM 		len = strlen(p) + 1;
12189139SJan.Pechanec@Sun.COM 		while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
12199139SJan.Pechanec@Sun.COM 			len += 1 + strlen(arg);
12209139SJan.Pechanec@Sun.COM 			p = xrealloc(p, len);
12219139SJan.Pechanec@Sun.COM 			strlcat(p, " ", len);
12229139SJan.Pechanec@Sun.COM 			strlcat(p, arg, len);
12239139SJan.Pechanec@Sun.COM 		}
12249139SJan.Pechanec@Sun.COM 		options->subsystem_args[options->num_subsystems] = p;
12250Sstevel@tonic-gate 		options->num_subsystems++;
12260Sstevel@tonic-gate 		break;
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	case sMaxStartups:
12290Sstevel@tonic-gate 		arg = strdelim(&cp);
12300Sstevel@tonic-gate 		if (!arg || *arg == '\0')
12310Sstevel@tonic-gate 			fatal("%s line %d: Missing MaxStartups spec.",
12320Sstevel@tonic-gate 			    filename, linenum);
12330Sstevel@tonic-gate 		if ((n = sscanf(arg, "%d:%d:%d",
12340Sstevel@tonic-gate 		    &options->max_startups_begin,
12350Sstevel@tonic-gate 		    &options->max_startups_rate,
12360Sstevel@tonic-gate 		    &options->max_startups)) == 3) {
12370Sstevel@tonic-gate 			if (options->max_startups_begin >
12380Sstevel@tonic-gate 			    options->max_startups ||
12390Sstevel@tonic-gate 			    options->max_startups_rate > 100 ||
12400Sstevel@tonic-gate 			    options->max_startups_rate < 1)
12410Sstevel@tonic-gate 				fatal("%s line %d: Illegal MaxStartups spec.",
12420Sstevel@tonic-gate 				    filename, linenum);
12430Sstevel@tonic-gate 		} else if (n != 1)
12440Sstevel@tonic-gate 			fatal("%s line %d: Illegal MaxStartups spec.",
12450Sstevel@tonic-gate 			    filename, linenum);
12460Sstevel@tonic-gate 		else
12470Sstevel@tonic-gate 			options->max_startups = options->max_startups_begin;
12480Sstevel@tonic-gate 		break;
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	case sBanner:
12510Sstevel@tonic-gate 		charptr = &options->banner;
12520Sstevel@tonic-gate 		goto parse_filename;
12530Sstevel@tonic-gate 	/*
12540Sstevel@tonic-gate 	 * These options can contain %X options expanded at
12550Sstevel@tonic-gate 	 * connect time, so that you can specify paths like:
12560Sstevel@tonic-gate 	 *
12570Sstevel@tonic-gate 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
12580Sstevel@tonic-gate 	 */
12590Sstevel@tonic-gate 	case sAuthorizedKeysFile:
12600Sstevel@tonic-gate 	case sAuthorizedKeysFile2:
12619139SJan.Pechanec@Sun.COM 		charptr = (opcode == sAuthorizedKeysFile) ?
12620Sstevel@tonic-gate 		    &options->authorized_keys_file :
12630Sstevel@tonic-gate 		    &options->authorized_keys_file2;
12640Sstevel@tonic-gate 		goto parse_filename;
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	case sClientAliveInterval:
12670Sstevel@tonic-gate 		intptr = &options->client_alive_interval;
12680Sstevel@tonic-gate 		goto parse_time;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	case sClientAliveCountMax:
12710Sstevel@tonic-gate 		intptr = &options->client_alive_count_max;
12720Sstevel@tonic-gate 		goto parse_int;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	case sMaxAuthTries:
12750Sstevel@tonic-gate 		intptr = &options->max_auth_tries;
12760Sstevel@tonic-gate 		goto parse_int;
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	case sMaxAuthTriesLog:
12790Sstevel@tonic-gate 		intptr = &options->max_auth_tries_log;
12800Sstevel@tonic-gate 		goto parse_int;
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	case sLookupClientHostnames:
12830Sstevel@tonic-gate 		intptr = &options->lookup_client_hostnames;
12840Sstevel@tonic-gate 		goto parse_flag;
12859139SJan.Pechanec@Sun.COM 
12867574SJan.Pechanec@Sun.COM 	case sUseOpenSSLEngine:
12877574SJan.Pechanec@Sun.COM 		intptr = &options->use_openssl_engine;
12887574SJan.Pechanec@Sun.COM 		goto parse_flag;
12890Sstevel@tonic-gate 
12909139SJan.Pechanec@Sun.COM 	case sChrootDirectory:
12919139SJan.Pechanec@Sun.COM 		charptr = &options->chroot_directory;
12929139SJan.Pechanec@Sun.COM 
12939139SJan.Pechanec@Sun.COM 		arg = strdelim(&cp);
12949139SJan.Pechanec@Sun.COM 		if (arg == NULL || *arg == '\0')
12959139SJan.Pechanec@Sun.COM 			fatal("%s line %d: missing directory name for "
12969139SJan.Pechanec@Sun.COM 			    "ChrootDirectory.", filename, linenum);
129711044SHuie-Ying.Lee@Sun.COM 		if (*activep && *charptr == NULL)
12989139SJan.Pechanec@Sun.COM 			*charptr = xstrdup(arg);
12999139SJan.Pechanec@Sun.COM 		break;
13009139SJan.Pechanec@Sun.COM 
130111044SHuie-Ying.Lee@Sun.COM 	case sMatch:
130211044SHuie-Ying.Lee@Sun.COM 		if (cmdline)
130311044SHuie-Ying.Lee@Sun.COM 			fatal("Match directive not supported as a command-line "
130411044SHuie-Ying.Lee@Sun.COM 			   "option");
130511044SHuie-Ying.Lee@Sun.COM 		value = match_cfg_line(&cp, linenum, user, host, address);
130611044SHuie-Ying.Lee@Sun.COM 		if (value < 0)
130711044SHuie-Ying.Lee@Sun.COM 			fatal("%s line %d: Bad Match condition", filename,
130811044SHuie-Ying.Lee@Sun.COM 			    linenum);
130911044SHuie-Ying.Lee@Sun.COM 		*activep = value;
131011044SHuie-Ying.Lee@Sun.COM 		break;
131111044SHuie-Ying.Lee@Sun.COM 
13120Sstevel@tonic-gate 	case sDeprecated:
13130Sstevel@tonic-gate 		log("%s line %d: Deprecated option %s",
13140Sstevel@tonic-gate 		    filename, linenum, arg);
13150Sstevel@tonic-gate 		while (arg)
13160Sstevel@tonic-gate 		    arg = strdelim(&cp);
13170Sstevel@tonic-gate 		break;
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	default:
13200Sstevel@tonic-gate 		fatal("%s line %d: Missing handler for opcode %s (%d)",
13210Sstevel@tonic-gate 		    filename, linenum, arg, opcode);
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate 	if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
13240Sstevel@tonic-gate 		fatal("%s line %d: garbage at end of line; \"%.200s\".",
13250Sstevel@tonic-gate 		    filename, linenum, arg);
13260Sstevel@tonic-gate 	return 0;
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate 
132911044SHuie-Ying.Lee@Sun.COM 
13300Sstevel@tonic-gate /* Reads the server configuration file. */
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate void
133311044SHuie-Ying.Lee@Sun.COM load_server_config(const char *filename, Buffer *conf)
13340Sstevel@tonic-gate {
133511044SHuie-Ying.Lee@Sun.COM 	char line[1024], *cp;
13360Sstevel@tonic-gate 	FILE *f;
13370Sstevel@tonic-gate 
133811044SHuie-Ying.Lee@Sun.COM 	debug2("%s: filename %s", __func__, filename);
133911044SHuie-Ying.Lee@Sun.COM 	if ((f = fopen(filename, "r")) == NULL) {
13400Sstevel@tonic-gate 		perror(filename);
13410Sstevel@tonic-gate 		exit(1);
13420Sstevel@tonic-gate 	}
134311044SHuie-Ying.Lee@Sun.COM 	buffer_clear(conf);
13440Sstevel@tonic-gate 	while (fgets(line, sizeof(line), f)) {
134511044SHuie-Ying.Lee@Sun.COM 		/*
134611044SHuie-Ying.Lee@Sun.COM 		 * Trim out comments and strip whitespace
134711044SHuie-Ying.Lee@Sun.COM 		 * NB - preserve newlines, they are needed to reproduce
134811044SHuie-Ying.Lee@Sun.COM 		 * line numbers later for error messages
134911044SHuie-Ying.Lee@Sun.COM 		 */
135011044SHuie-Ying.Lee@Sun.COM 		if ((cp = strchr(line, '#')) != NULL)
135111044SHuie-Ying.Lee@Sun.COM 			memcpy(cp, "\n", 2);
135211044SHuie-Ying.Lee@Sun.COM 		cp = line + strspn(line, " \t\r");
135311044SHuie-Ying.Lee@Sun.COM 
135411044SHuie-Ying.Lee@Sun.COM 		buffer_append(conf, cp, strlen(cp));
135511044SHuie-Ying.Lee@Sun.COM 	}
135611044SHuie-Ying.Lee@Sun.COM 	buffer_append(conf, "\0", 1);
135711044SHuie-Ying.Lee@Sun.COM 	fclose(f);
135811044SHuie-Ying.Lee@Sun.COM 	debug2("%s: done config len = %d", __func__, buffer_len(conf));
135911044SHuie-Ying.Lee@Sun.COM }
136011044SHuie-Ying.Lee@Sun.COM 
136111044SHuie-Ying.Lee@Sun.COM void
136211044SHuie-Ying.Lee@Sun.COM parse_server_match_config(ServerOptions *options, const char *user,
136311044SHuie-Ying.Lee@Sun.COM     const char *host, const char *address)
136411044SHuie-Ying.Lee@Sun.COM {
136511044SHuie-Ying.Lee@Sun.COM 	ServerOptions mo;
136611044SHuie-Ying.Lee@Sun.COM 
136711044SHuie-Ying.Lee@Sun.COM 	initialize_server_options(&mo);
136811044SHuie-Ying.Lee@Sun.COM 	parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
136911044SHuie-Ying.Lee@Sun.COM 	copy_set_server_options(options, &mo, 0);
137011044SHuie-Ying.Lee@Sun.COM }
137111044SHuie-Ying.Lee@Sun.COM 
137211044SHuie-Ying.Lee@Sun.COM 
137311044SHuie-Ying.Lee@Sun.COM 
137411044SHuie-Ying.Lee@Sun.COM /* Helper macros */
137511044SHuie-Ying.Lee@Sun.COM #define M_CP_INTOPT(n) do {\
137611044SHuie-Ying.Lee@Sun.COM 	if (src->n != -1) \
137711044SHuie-Ying.Lee@Sun.COM 		dst->n = src->n; \
137811044SHuie-Ying.Lee@Sun.COM } while (0)
137911044SHuie-Ying.Lee@Sun.COM #define M_CP_STROPT(n) do {\
138011044SHuie-Ying.Lee@Sun.COM 	if (src->n != NULL) { \
138111044SHuie-Ying.Lee@Sun.COM 		if (dst->n != NULL) \
138211044SHuie-Ying.Lee@Sun.COM 			xfree(dst->n); \
138311044SHuie-Ying.Lee@Sun.COM 		dst->n = src->n; \
138411044SHuie-Ying.Lee@Sun.COM 	} \
138511044SHuie-Ying.Lee@Sun.COM } while(0)
138611044SHuie-Ying.Lee@Sun.COM 
138711044SHuie-Ying.Lee@Sun.COM /*
138811044SHuie-Ying.Lee@Sun.COM  * Copy any supported values that are set.
138911044SHuie-Ying.Lee@Sun.COM  *
139011044SHuie-Ying.Lee@Sun.COM  * If the preauth flag is set, we do not bother copying the the string or
139111044SHuie-Ying.Lee@Sun.COM  * array values that are not used pre-authentication, because any that we
139211044SHuie-Ying.Lee@Sun.COM  * do use must be explictly sent in mm_getpwnamallow().
139311044SHuie-Ying.Lee@Sun.COM  */
139411044SHuie-Ying.Lee@Sun.COM void
139511044SHuie-Ying.Lee@Sun.COM copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
139611044SHuie-Ying.Lee@Sun.COM {
139711044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(password_authentication);
139811044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(gss_authentication);
139911044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(rsa_authentication);
140011044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(pubkey_authentication);
140111044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(hostbased_authentication);
140211044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(kbd_interactive_authentication);
140311044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(permit_root_login);
140411044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(permit_empty_passwd);
140511044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(allow_tcp_forwarding);
140611044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(gateway_ports);
140711044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(x11_display_offset);
140811044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(x11_forwarding);
140911044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(x11_use_localhost);
141011044SHuie-Ying.Lee@Sun.COM 	M_CP_INTOPT(max_auth_tries);
141111044SHuie-Ying.Lee@Sun.COM 	M_CP_STROPT(banner);
141211044SHuie-Ying.Lee@Sun.COM 
141311044SHuie-Ying.Lee@Sun.COM 	if (preauth)
141411044SHuie-Ying.Lee@Sun.COM 		return;
141511044SHuie-Ying.Lee@Sun.COM 	M_CP_STROPT(chroot_directory);
141611044SHuie-Ying.Lee@Sun.COM }
141711044SHuie-Ying.Lee@Sun.COM 
141811044SHuie-Ying.Lee@Sun.COM #undef M_CP_INTOPT
141911044SHuie-Ying.Lee@Sun.COM #undef M_CP_STROPT
142011044SHuie-Ying.Lee@Sun.COM 
142111044SHuie-Ying.Lee@Sun.COM void
142211044SHuie-Ying.Lee@Sun.COM parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
142311044SHuie-Ying.Lee@Sun.COM     const char *user, const char *host, const char *address)
142411044SHuie-Ying.Lee@Sun.COM {
142511044SHuie-Ying.Lee@Sun.COM 	int active, linenum, bad_options = 0;
142611044SHuie-Ying.Lee@Sun.COM 	char *cp, *obuf, *cbuf;
142711044SHuie-Ying.Lee@Sun.COM 
142811044SHuie-Ying.Lee@Sun.COM 	debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
142911044SHuie-Ying.Lee@Sun.COM 
143011044SHuie-Ying.Lee@Sun.COM 	obuf = cbuf = xstrdup(buffer_ptr(conf));
143111044SHuie-Ying.Lee@Sun.COM 	active = user ? 0 : 1;
143211044SHuie-Ying.Lee@Sun.COM 	linenum = 1;
143311044SHuie-Ying.Lee@Sun.COM 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
143411044SHuie-Ying.Lee@Sun.COM 		if (process_server_config_line(options, cp, filename,
143511044SHuie-Ying.Lee@Sun.COM 		    linenum++, &active, user, host, address) != 0)
14360Sstevel@tonic-gate 			bad_options++;
14370Sstevel@tonic-gate 	}
143811044SHuie-Ying.Lee@Sun.COM 	xfree(obuf);
14390Sstevel@tonic-gate 	if (bad_options > 0)
14400Sstevel@tonic-gate 		fatal("%s: terminating, %d bad configuration options",
14410Sstevel@tonic-gate 		    filename, bad_options);
14420Sstevel@tonic-gate }
14439139SJan.Pechanec@Sun.COM 
144411044SHuie-Ying.Lee@Sun.COM 
14459139SJan.Pechanec@Sun.COM /*
14469139SJan.Pechanec@Sun.COM  * Note that "none" is a special path having the same affect on sshd
14479139SJan.Pechanec@Sun.COM  * configuration as not specifying ChrootDirectory at all.
14489139SJan.Pechanec@Sun.COM  */
14499139SJan.Pechanec@Sun.COM int
14509139SJan.Pechanec@Sun.COM chroot_requested(char *chroot_directory)
14519139SJan.Pechanec@Sun.COM {
14529139SJan.Pechanec@Sun.COM 	return (chroot_directory != NULL &&
14539139SJan.Pechanec@Sun.COM 	    strcasecmp(chroot_directory, "none") != 0);
14549139SJan.Pechanec@Sun.COM }
1455