1 /*
2 * ProFTPD - mod_sftp 'hostbased' user authentication
3 * Copyright (c) 2008-2020 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 */
24
25 #include "mod_sftp.h"
26 #include "ssh2.h"
27 #include "packet.h"
28 #include "msg.h"
29 #include "auth.h"
30 #include "session.h"
31 #include "keys.h"
32 #include "keystore.h"
33 #include "interop.h"
34 #include "blacklist.h"
35 #include "utf8.h"
36
37 static const char *trace_channel = "ssh2";
38
sftp_auth_hostbased(struct ssh2_packet * pkt,cmd_rec * pass_cmd,const char * orig_user,const char * user,const char * service,unsigned char ** buf,uint32_t * buflen,int * send_userauth_fail)39 int sftp_auth_hostbased(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
40 const char *orig_user, const char *user, const char *service,
41 unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) {
42 struct passwd *pw;
43 char *hostkey_algo, *host_fqdn, *host_user, *host_user_utf8;
44 const char *fp = NULL, *fp_algo = NULL;
45 unsigned char *hostkey_data, *signature_data;
46 unsigned char *buf2, *ptr2;
47 const unsigned char *id;
48 uint32_t buflen2, bufsz2, hostkey_datalen, id_len, signature_len;
49 enum sftp_key_type_e pubkey_type;
50 int fp_algo_id;
51
52 if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) {
53 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
54 "authentication request for user '%s' blocked by '%s' handler",
55 orig_user, (char *) pass_cmd->argv[0]);
56
57 pr_log_auth(PR_LOG_NOTICE,
58 "USER %s (Login failed): blocked by '%s' handler", orig_user,
59 (char *) pass_cmd->argv[0]);
60
61 pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
62 pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);
63
64 *send_userauth_fail = TRUE;
65 errno = EPERM;
66 return 0;
67 }
68
69 hostkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen);
70 if (hostkey_algo == NULL) {
71 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
72 "missing required host key algorithm, rejecting request");
73
74 *send_userauth_fail = TRUE;
75 errno = EINVAL;
76 return 0;
77 }
78
79 hostkey_datalen = sftp_msg_read_int(pkt->pool, buf, buflen);
80 hostkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, hostkey_datalen);
81
82 host_fqdn = sftp_msg_read_string(pkt->pool, buf, buflen);
83
84 host_user_utf8 = sftp_msg_read_string(pkt->pool, buf, buflen);
85 host_user = sftp_utf8_decode_str(pkt->pool, host_user_utf8);
86
87 signature_len = sftp_msg_read_int(pkt->pool, buf, buflen);
88 signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len);
89
90 pr_trace_msg(trace_channel, 9,
91 "client sent '%s' host key, FQDN %s, and remote user '%s'",
92 hostkey_algo, host_fqdn, host_user);
93
94 if (strncmp(hostkey_algo, "ssh-rsa", 8) == 0) {
95 pubkey_type = SFTP_KEY_RSA;
96
97 #ifdef HAVE_SHA256_OPENSSL
98 } else if (strncmp(hostkey_algo, "rsa-sha2-256", 13) == 0) {
99 pubkey_type = SFTP_KEY_RSA_SHA256;
100 #endif /* HAVE_SHA256_OPENSSL */
101
102 #ifdef HAVE_SHA512_OPENSSL
103 } else if (strncmp(hostkey_algo, "rsa-sha2-512", 13) == 0) {
104 pubkey_type = SFTP_KEY_RSA_SHA512;
105 #endif /* HAVE_SHA512_OPENSSL */
106
107 } else if (strncmp(hostkey_algo, "ssh-dss", 8) == 0) {
108 pubkey_type = SFTP_KEY_DSA;
109
110 #ifdef PR_USE_OPENSSL_ECC
111 } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
112 pubkey_type = SFTP_KEY_ECDSA_256;
113
114 } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp384", 20) == 0) {
115 pubkey_type = SFTP_KEY_ECDSA_384;
116
117 } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp521", 20) == 0) {
118 pubkey_type = SFTP_KEY_ECDSA_521;
119 #endif /* PR_USE_OPENSSL_ECC */
120
121 /* XXX Need to support X509v3 certs here */
122
123 } else {
124 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
125 "unsupported host key algorithm '%s' requested, rejecting request",
126 hostkey_algo);
127
128 pr_log_auth(PR_LOG_NOTICE,
129 "USER %s (Login failed): unsupported host key algorithm '%s' requested",
130 user, hostkey_algo);
131
132 *send_userauth_fail = TRUE;
133 errno = EINVAL;
134 return 0;
135 }
136
137 if (sftp_keys_verify_pubkey_type(pkt->pool, hostkey_data, hostkey_datalen,
138 pubkey_type) != TRUE) {
139 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
140 "unable to verify that given host key matches given '%s' algorithm",
141 hostkey_algo);
142
143 *send_userauth_fail = TRUE;
144 errno = EINVAL;
145 return 0;
146 }
147
148 #ifdef OPENSSL_FIPS
149 if (FIPS_mode()) {
150 # if defined(HAVE_SHA256_OPENSSL)
151 fp_algo_id = SFTP_KEYS_FP_DIGEST_SHA256;
152 fp_algo = "SHA256";
153 # else
154 fp_algo_id = SFTP_KEYS_FP_DIGEST_SHA1;
155 fp_algo = "SHA1";
156 # endif /* HAVE_SHA256_OPENSSL */
157
158 fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen,
159 fp_algo_id);
160 if (fp != NULL) {
161 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
162 "public key %s fingerprint: %s", fp_algo, fp);
163
164 } else {
165 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
166 "error obtaining public key %s fingerprint: %s", fp_algo,
167 strerror(errno));
168 }
169
170 } else {
171 #endif /* OPENSSL_FIPS */
172 #if defined(HAVE_SHA256_OPENSSL)
173 fp_algo_id = SFTP_KEYS_FP_DIGEST_SHA256;
174 fp_algo = "SHA256";
175 #else
176 fp_algo_id = SFTP_KEYS_FP_DIGEST_MD5;
177 fp_algo = "MD5";
178 #endif /* HAVE_SHA256_OPENSSL */
179
180 fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen,
181 fp_algo_id);
182 if (fp != NULL) {
183 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
184 "public key %s fingerprint: %s", fp_algo, fp);
185
186 } else {
187 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
188 "error obtaining public key %s fingerprint: %s", fp_algo,
189 strerror(errno));
190 }
191 #ifdef OPENSSL_FIPS
192 }
193 #endif /* OPENSSL_FIPS */
194
195 pw = pr_auth_getpwnam(pkt->pool, user);
196 if (pw == NULL) {
197 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
198 "no account for user '%s' found", user);
199
200 pr_log_auth(PR_LOG_NOTICE,
201 "USER %s: no such user found from %s [%s] to %s:%d", user,
202 session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr),
203 pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port);
204
205 *send_userauth_fail = TRUE;
206 errno = ENOENT;
207 return 0;
208 }
209
210 /* XXX Should we check the given FQDN here against the client's actual
211 * DNS name and/or IP address? Or leave that up to the keystore's
212 * verify_host_key() function?
213 */
214
215 if (sftp_blacklist_reject_key(pkt->pool, hostkey_data, hostkey_datalen)) {
216 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): requested host "
217 "key is blacklisted", user);
218
219 *send_userauth_fail = TRUE;
220 errno = EACCES;
221 return 0;
222 }
223
224 /* The client signed the request as well; we need to authenticate the
225 * host with the given key now. If that succeeds, we use the signature to
226 * verify the request. And if that succeeds, then we're done authenticating.
227 */
228
229 if (sftp_keystore_verify_host_key(pkt->pool, user, host_fqdn, host_user,
230 hostkey_data, hostkey_datalen) < 0) {
231 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): authentication "
232 "via '%s' host key failed", user, hostkey_algo);
233
234 *send_userauth_fail = TRUE;
235 errno = EACCES;
236 return 0;
237 }
238
239 /* Make sure the signature matches as well. */
240
241 id_len = sftp_session_get_id(&id);
242
243 /* XXX Is this buffer large enough? Too large? */
244 bufsz2 = buflen2 = 2048;
245 ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2);
246
247 sftp_msg_write_data(&buf2, &buflen2, id, id_len, TRUE);
248 sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST);
249 sftp_msg_write_string(&buf2, &buflen2, orig_user);
250
251 if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_HOST_SIG)) {
252 sftp_msg_write_string(&buf2, &buflen2, service);
253
254 } else {
255 sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth");
256 }
257
258 sftp_msg_write_string(&buf2, &buflen2, "hostbased");
259 sftp_msg_write_string(&buf2, &buflen2, hostkey_algo);
260 sftp_msg_write_data(&buf2, &buflen2, hostkey_data, hostkey_datalen, TRUE);
261 sftp_msg_write_string(&buf2, &buflen2, host_fqdn);
262 sftp_msg_write_string(&buf2, &buflen2, host_user_utf8);
263
264 if (sftp_keys_verify_signed_data(pkt->pool, hostkey_algo, hostkey_data,
265 hostkey_datalen, signature_data, signature_len, (unsigned char *) ptr2,
266 (bufsz2 - buflen2)) < 0) {
267 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
268 "failed to verify '%s' signature on hostbased auth request for "
269 "user '%s', host %s", hostkey_algo, orig_user, host_fqdn);
270
271 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): signature "
272 "verification of '%s' host key failed", user, hostkey_algo);
273
274 *send_userauth_fail = TRUE;
275 errno = EACCES;
276 return 0;
277 }
278
279 /* Make sure the user is authorized to login. Normally this is checked
280 * as part of the password verification process, but in the case of
281 * hostbased authentication, there is no password to verify.
282 */
283
284 if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) {
285 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
286 "authentication for user '%s' failed: User not authorized", user);
287 pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized "
288 "for login", user);
289 *send_userauth_fail = TRUE;
290 errno = EACCES;
291 return 0;
292 }
293
294 return 1;
295 }
296
sftp_auth_hostbased_init(pool * p)297 int sftp_auth_hostbased_init(pool *p) {
298 return 0;
299 }
300