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