Project

General

Profile

Download (8.49 KB) Statistics
| Branch: | Tag: | Revision:
1
#!/usr/local/bin/php-cgi -f
2
<?php
3
/*
4
 * sshd
5
 *
6
 * part of pfSense (https://www.pfsense.org)
7
 * Copyright (c) 2004 Fred Mol <fredmol@xs4all.nl>.
8
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions are met:
13
 *
14
 * 1. Redistributions of source code must retain the above copyright notice,
15
 *    this list of conditions and the following disclaimer.
16
 *
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in
19
 *    the documentation and/or other materials provided with the
20
 *    distribution.
21
 *
22
 * 3. All advertising materials mentioning features or use of this software
23
 *    must display the following acknowledgment:
24
 *    "This product includes software developed by the pfSense Project
25
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
26
 *
27
 * 4. The names "pfSense" and "pfSense Project" must not be used to
28
 *    endorse or promote products derived from this software without
29
 *    prior written permission. For written permission, please contact
30
 *    coreteam@pfsense.org.
31
 *
32
 * 5. Products derived from this software may not be called "pfSense"
33
 *    nor may "pfSense" appear in their names without prior written
34
 *    permission of the Electric Sheep Fencing, LLC.
35
 *
36
 * 6. Redistributions of any form whatsoever must retain the following
37
 *    acknowledgment:
38
 *
39
 * "This product includes software developed by the pfSense Project
40
 * for use in the pfSense software distribution (http://www.pfsense.org/).
41
 *
42
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
43
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
46
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
51
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
53
 * OF THE POSSIBILITY OF SUCH DAMAGE.
54
 */
55

    
56
require_once("globals.inc");
57
require_once("config.inc");
58
require_once("functions.inc");
59
require_once("shaper.inc");
60

    
61
if (!isset($config['system']['enablesshd'])) {
62
	return;
63
}
64

    
65
/* are we already running?  if not, do conf_mount_rw(), otherwise it should already be rw */
66
if (!is_subsystem_dirty('sshdkeys')) {
67
	conf_mount_rw();
68
}
69

    
70
$sshConfigDir = "/etc/ssh";
71

    
72
$keys = array(
73
	array('type' => 'rsa',     'suffix' => 'rsa_'),
74
	array('type' => 'ed25519', 'suffix' => 'ed25519_')
75
);
76

    
77
$keyfiles = array();
78
foreach ($keys as $key) {
79
	$keyfiles[] = "ssh_host_{$key['suffix']}key";
80
	$keyfiles[] = "ssh_host_{$key['suffix']}key.pub";
81
}
82

    
83
/* restore ssh data for nanobsd platform */
84
if ($g['platform'] == "nanobsd" and file_exists("/conf/sshd/ssh_host_key") and !file_exists("{$sshConfigDir}/ssh_host_key.pub")) {
85
	echo "Restoring SSH from /conf/sshd/";
86
	exec("/bin/cp -p /conf/sshd/* {$sshConfigDir}/");
87

    
88
	/* make sure host private key permissions aren't too open so sshd won't complain */
89
	foreach ($keyfiles as $f2c) {
90
		if (file_exists("{$sshConfigDir}/{$f2c}")) {
91
			chmod("{$sshConfigDir}/{$f2c}", 0600);
92
		}
93
	}
94
}
95

    
96
/*    if any of these files are 0 bytes then they are corrupted.
97
 *    remove them
98
 */
99
foreach ($keyfiles as $f2c) {
100
	if (!file_exists("{$sshConfigDir}/{$f2c}") || filesize("{$sshConfigDir}/{$f2c}") == 0) {
101
		/* Make sure we remove both files */
102
		unlink_if_exists($sshConfigDir . '/' . basename($f2c, ".pub"));
103
		unlink_if_exists($sshConfigDir . '/' . $f2c);
104
	}
105
}
106

    
107
if (!is_dir("/var/empty")) {
108
	/* make ssh home directory */
109
	mkdir("/var/empty", 0555);
110
}
111

    
112
if (!file_exists("/var/log/lastlog")) {
113
	/* Login related files. */
114
	@touch("/var/log/lastlog");
115
}
116

    
117
if (is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
118
	$sshport = $config['system']['ssh']['port'];
119
} else {
120
	$sshport = 22;
121
}
122

    
123
/* Include default configuration for pfSense */
124
/* Taken from https://stribika.github.io/2015/01/04/secure-secure-shell.html */
125
$sshconf = "# This file is automatically generated at startup\n";
126
$sshconf .= "KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256\n";
127
/* Run the server on another port if we have one defined */
128
$sshconf .= "Port $sshport\n";
129
/* Only allow protocol 2, because we say so */
130
$sshconf .= "Protocol 2\n";
131
foreach ($keys as $key) {
132
	$sshconf .= "HostKey {$sshConfigDir}/ssh_host_{$key['suffix']}key\n";
133
}
134
$sshconf .= "Compression yes\n";
135
$sshconf .= "ClientAliveInterval 30\n";
136
$sshconf .= "PermitRootLogin yes\n";
137
if (isset($config['system']['ssh']['sshdkeyonly'])) {
138
	$sshconf .= "# Login via Key only\n";
139
	$sshconf .= "ChallengeResponseAuthentication no\n";
140
	$sshconf .= "PasswordAuthentication no\n";
141
	$sshconf .= "PubkeyAuthentication yes\n";
142
	$sshconf .= "UsePAM no\n";
143
} else {
144
	$sshconf .= "# Login via Key and Password\n";
145
	$sshconf .= "ChallengeResponseAuthentication yes\n";
146
	$sshconf .= "PasswordAuthentication yes\n";
147
	$sshconf .= "PubkeyAuthentication yes\n";
148
}
149
$sshconf .= "UseDNS no\n";
150
$sshconf .= "LoginGraceTime 30s\n";
151
/* Hide FreeBSD version */
152
$sshconf .= "VersionAddendum none\n";
153
$sshconf .= "X11Forwarding no\n";
154
$sshconf .= "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr\n";
155
$sshconf .= "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com\n";
156
$sshconf .= "# override default of no subsystems\n";
157
$sshconf .= "Subsystem\tsftp\t/usr/libexec/sftp-server\n";
158

    
159
/* Apply package SSHDCond settings if config file exists */
160
if (file_exists("/etc/sshd_extra")) {
161
	$fdExtra = fopen("/etc/sshd_extra", 'r');
162
	$szExtra = fread($fdExtra, 1048576); // Read up to 1MB from extra file
163
	$sshconf .= $szExtra;
164
	fclose($fdExtra);
165
}
166

    
167
/* Write the new sshd config file */
168
@file_put_contents("{$sshConfigDir}/sshd_config", $sshconf);
169

    
170
/* mop up from a badly implemented ssh keys -> cf backup */
171
if ($config['ssh']['dsa_key'] <> "") {
172
	unset($config['ssh']['dsa_key']);
173
	unset($config['ssh']['ecdsa_key']);
174
	unset($config['ssh']['ed25519_key']);
175
	unset($config['ssh']['rsa_key']);
176
	unset($config['ssh']['rsa1_key']);
177
	unset($config['ssh']['dsa']);
178
	unset($config['ssh']['rsa']);
179
	unset($config['ssh']['rsa1']);
180
	unset($config['ssh']['ak']);
181
	write_config("Clearing SSH keys from config.xml");
182
}
183

    
184
/* are we already running?  if so exit */
185
if (is_subsystem_dirty('sshdkeys')) {
186
	unset($keys, $keyfiles);
187
	return;
188
}
189

    
190
// Check for all needed key files. If any are missing, the keys need to be regenerated.
191
$generate_keys = array();
192
foreach ($keys as $key) {
193
	if (!file_exists("{$sshConfigDir}/ssh_host_{$key['suffix']}key") ||
194
	    !file_exists("{$sshConfigDir}/ssh_host_{$key['suffix']}key.pub")) {
195
		$generate_keys[] = $key;
196
	}
197
}
198

    
199
if (!empty($generate_keys)) {
200
	/* remove previous keys and regen later */
201
	file_notice("SSH", "{$g['product_name']} has started creating missing SSH keys.  SSH Startup will be delayed.  Please note that reloading the filter rules and changes will be delayed until this operation is completed.", "SSH KeyGen", "");
202
	mark_subsystem_dirty('sshdkeys');
203
	echo " Generating Keys:\n";
204
	foreach ($generate_keys as $key) {
205
		$_gb = exec("/usr/bin/nice -n20 /usr/bin/ssh-keygen -t {$key['type']} -b 4096 -N '' -f {$sshConfigDir}/ssh_host_{$key['suffix']}key");
206
	}
207
	clear_subsystem_dirty('sshdkeys');
208
	file_notice("SSH", "{$g['product_name']} has completed creating your SSH keys.  SSH is now started.", "SSH Startup", "");
209
}
210

    
211
/* kill existing sshd process, server only, not the childs */
212
$sshd_pid = exec("ps ax | egrep '/usr/sbin/[s]shd' | awk '{print $1}'");
213
if ($sshd_pid <> "") {
214
	echo "stopping ssh process $sshd_pid \n";
215
	@posix_kill($sshd_pid, SIGTERM);
216
}
217
/* Launch new server process */
218
$status = mwexec("/usr/sbin/sshd");
219
if ($status <> 0) {
220
	file_notice("sshd_startup", "SSHD failed to start.", "SSHD Daemon", "");
221
	echo "error!\n";
222
} else {
223
	echo "done.\n";
224
}
225

    
226
// NanoBSD
227
if ($g['platform'] == "nanobsd") {
228
	if (!is_dir("/conf/sshd")) {
229
		mkdir("/conf/sshd", 0750);
230
	}
231
	$_gb = exec("/bin/cp -p {$sshConfigDir}/ssh_host* /conf/sshd");
232
}
233
conf_mount_ro();
234
unset($keys, $keyfiles);
235
?>
(91-91/94)