1 /*
2  * ProFTPD - mod_sftp
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  * -----DO NOT EDIT BELOW THIS LINE-----
25  * $Archive: mod_sftp.a$
26  * $Libraries: -lcrypto$
27  */
28 
29 #include "mod_sftp.h"
30 #include "ssh2.h"
31 #include "packet.h"
32 #include "interop.h"
33 #include "crypto.h"
34 #include "cipher.h"
35 #include "mac.h"
36 #include "keys.h"
37 #include "keystore.h"
38 #include "disconnect.h"
39 #include "kex.h"
40 #include "blacklist.h"
41 #include "service.h"
42 #include "auth.h"
43 #include "channel.h"
44 #include "tap.h"
45 #include "kbdint.h"
46 #include "fxp.h"
47 #include "utf8.h"
48 
49 #if defined(HAVE_SODIUM_H)
50 # include <sodium.h>
51 #endif /* HAVE_SODIUM_H */
52 
53 extern xaset_t *server_list;
54 
55 module sftp_module;
56 
57 int sftp_logfd = -1;
58 const char *sftp_logname = NULL;
59 pool *sftp_pool = NULL;
60 conn_t *sftp_conn = NULL;
61 unsigned int sftp_sess_state = 0;
62 unsigned long sftp_opts = 0UL;
63 unsigned int sftp_services = SFTP_SERVICE_DEFAULT;
64 
65 static int sftp_engine = 0;
66 static const char *sftp_client_version = NULL;
67 static const char *sftp_server_version = SFTP_ID_DEFAULT_STRING;
68 
69 /* Flags for changing how hostkeys are handled. */
70 #define SFTP_HOSTKEY_FL_CLEAR_RSA_KEY		0x001
71 #define SFTP_HOSTKEY_FL_CLEAR_DSA_KEY		0x002
72 #define SFTP_HOSTKEY_FL_CLEAR_ECDSA_KEY		0x004
73 #define SFTP_HOSTKEY_FL_CLEAR_ED25519_KEY	0x008
74 
75 static const char *trace_channel = "ssh2";
76 
sftp_have_authenticated(cmd_rec * cmd)77 static int sftp_have_authenticated(cmd_rec *cmd) {
78   return (sftp_sess_state & SFTP_SESS_STATE_HAVE_AUTH);
79 }
80 
sftp_get_client_version(conn_t * conn)81 static int sftp_get_client_version(conn_t *conn) {
82   int res;
83 
84   /* 255 is the RFC-defined maximum banner/ID string size */
85   char buf[256], *banner = NULL;
86   size_t buflen = 0;
87 
88   /* Read client version.  This looks ugly, reading one byte at a time.
89    * It is necessary, though.  The banner sent by the client is not of any
90    * guaranteed length.  The client might also send the next SSH packet in
91    * the exchange, such that both messages are in the socket buffer.  If
92    * we read too much of the banner, we'll read into the KEXINIT, for example,
93    * and cause problems later.
94    */
95 
96   while (TRUE) {
97     register unsigned int i;
98     int bad_proto = FALSE;
99 
100     pr_signals_handle();
101 
102     memset(buf, '\0', sizeof(buf));
103 
104     for (i = 0; i < sizeof(buf) - 1; i++) {
105       res = sftp_ssh2_packet_sock_read(conn->rfd, &buf[i], 1, 0);
106       while (res <= 0) {
107         int xerrno = errno;
108 
109         if (xerrno == EINTR) {
110           pr_signals_handle();
111 
112           res = sftp_ssh2_packet_sock_read(conn->rfd, &buf[i], 1, 0);
113           continue;
114         }
115 
116         if (res < 0) {
117           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
118             "error reading from client rfd %d: %s", conn->rfd,
119             strerror(xerrno));
120         }
121 
122         errno = xerrno;
123         return res;
124       }
125 
126       /* We continue reading until the client has sent the terminating
127        * CRLF sequence.
128        */
129       if (buf[i] == '\r') {
130         buf[i] = '\0';
131         continue;
132       }
133 
134       if (buf[i] == '\n') {
135         buf[i] = '\0';
136         break;
137       }
138     }
139 
140     if (i == sizeof(buf)-1) {
141       bad_proto = TRUE;
142 
143     } else {
144       buf[sizeof(buf)-1] = '\0';
145       buflen = strlen(buf);
146     }
147 
148     /* If the line does not begin with "SSH-2.0-", skip it.  RFC4253, Section
149      * 4.2 does not specify what should happen if the client sends data
150      * other than the proper version string initially.
151      *
152      * If we have been configured for compatibility with old protocol
153      * implementations, check for "SSH-1.99-" as well.
154      *
155      * OpenSSH simply disconnects the client after saying "Protocol mismatch"
156      * if the client's version string does not begin with "SSH-2.0-"
157      * (or "SSH-1.99-").  Works for me.
158      */
159     if (bad_proto == FALSE) {
160       if (strncmp(buf, "SSH-2.0-", 8) != 0) {
161         bad_proto = TRUE;
162 
163         if (sftp_opts & SFTP_OPT_OLD_PROTO_COMPAT) {
164           if (strncmp(buf, "SSH-1.99-", 9) == 0) {
165             if (buflen == 9) {
166               /* The client sent ONLY "SSH-1.99-".  OpenSSH handles this as a
167                * "Protocol mismatch", so shall we.
168                */
169               bad_proto = TRUE;
170 
171             } else {
172               banner = buf + 9;
173               bad_proto = FALSE;
174             }
175           }
176         }
177 
178       } else {
179         if (buflen == 8) {
180           /* The client sent ONLY "SSH-2.0-".  OpenSSH handles this as a
181            * "Protocol mismatch", so shall we.
182            */
183           bad_proto = TRUE;
184 
185         } else {
186           banner = buf + 8;
187         }
188       }
189     }
190 
191     if (banner != NULL) {
192       char *k, *v;
193 
194       k = pstrdup(session.pool, "SFTP_CLIENT_BANNER");
195       v = pstrdup(session.pool, banner);
196       pr_env_unset(session.pool, k);
197       pr_env_set(session.pool, k, v);
198       (void) pr_table_add(session.notes, k, v, 0);
199     }
200 
201     if (bad_proto) {
202       const char *errstr = "Protocol mismatch.\n";
203 
204       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
205         "Bad protocol version '%.100s' from %s", buf,
206         pr_netaddr_get_ipstr(session.c->remote_addr));
207 
208       if (write(conn->wfd, errstr, strlen(errstr)) < 0) {
209         pr_trace_msg("ssh2", 9,
210           "error sending 'Protocol mismatch' message to client: %s",
211           strerror(errno));
212       }
213 
214       errno = EINVAL;
215       return -1;
216     }
217 
218     break;
219   }
220 
221   sftp_client_version = pstrdup(sftp_pool, buf);
222   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
223     "received client version '%s'", sftp_client_version);
224 
225   if (sftp_interop_handle_version(sftp_pool, sftp_client_version) < 0) {
226     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
227       "error checking client version '%s' for interoperability: %s",
228       sftp_client_version, strerror(errno));
229   }
230 
231   return 0;
232 }
233 
sftp_cmd_loop(server_rec * s,conn_t * conn)234 static void sftp_cmd_loop(server_rec *s, conn_t *conn) {
235   int res;
236   char buf[256];
237   const char *k, *v;
238 
239   sftp_conn = conn;
240   pr_session_set_protocol("ssh2");
241 
242   if (sftp_opts & SFTP_OPT_PESSIMISTIC_KEXINIT) {
243     /* If we are being pessimistic, we will send our version string to the
244      * client now, and send our KEXINIT message later.
245      */
246     res = sftp_ssh2_packet_send_version();
247 
248   } else {
249     /* If we are being optimistic, we can reduce the connection latency
250      * by sending our KEXINIT message now; this will have the server version
251      * string automatically prepended.
252      */
253     res = sftp_kex_send_first_kexinit();
254   }
255 
256   if (res < 0) {
257     pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BY_APPLICATION,
258       NULL);
259   }
260 
261   res = sftp_get_client_version(conn);
262   if (res < 0) {
263     pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BY_APPLICATION,
264       NULL);
265   }
266 
267   sftp_kex_init(sftp_client_version, sftp_server_version);
268   sftp_service_init();
269   sftp_auth_init();
270   sftp_channel_init();
271 
272   /* Set the initial timeout for reading packets from clients.  Using
273    * a value of zero sets the default timeout value (i.e. TimeoutIdle).
274    */
275   sftp_ssh2_packet_set_poll_timeout(0);
276 
277   k = pstrdup(session.pool, "SFTP");
278   v = pstrdup(session.pool, "1");
279   pr_env_set(session.pool, k, v);
280   (void) pr_table_add(session.notes, k, v, 0);
281 
282   k = pstrdup(session.pool, "SFTP_LIBRARY_VERSION");
283   v = pstrdup(session.pool, OPENSSL_VERSION_TEXT);
284   pr_env_set(session.pool, k, v);
285   (void) pr_table_add(session.notes, k, v, 0);
286 
287   memset(buf, '\0', sizeof(buf));
288   k = pstrdup(session.pool, "SSH_CONNECTION");
289   pr_snprintf(buf, sizeof(buf)-1, "%.50s %d %.50s %d",
290     pr_netaddr_get_ipstr(conn->remote_addr), conn->remote_port,
291     pr_netaddr_get_ipstr(conn->local_addr), conn->local_port);
292   v = pstrdup(session.pool, buf);
293   pr_env_set(session.pool, k, v);
294   (void) pr_table_add(session.notes, k, v, 0);
295 
296   /* If we didn't send our KEXINIT earlier, send it now. */
297   if (sftp_opts & SFTP_OPT_PESSIMISTIC_KEXINIT) {
298     res = sftp_kex_send_first_kexinit();
299     if (res < 0) {
300       pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BY_APPLICATION,
301         NULL);
302     }
303   }
304 
305   while (TRUE) {
306     pr_signals_handle();
307 
308     res = sftp_ssh2_packet_handle();
309     if (res < 0) {
310       break;
311     }
312   }
313 
314   return;
315 }
316 
317 /* Configuration handlers
318  */
319 
320 /* usage: SFTPAcceptEnv env1 ... envN */
set_sftpacceptenv(cmd_rec * cmd)321 MODRET set_sftpacceptenv(cmd_rec *cmd) {
322   register unsigned int i;
323   config_rec *c;
324   array_header *accepted_envs;
325 
326   if (cmd->argc < 2) {
327     CONF_ERROR(cmd, "wrong number of parameters");
328   }
329 
330   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
331 
332   c = add_config_param(cmd->argv[0], 1, NULL);
333   accepted_envs = make_array(c->pool, 0, sizeof(char *));
334 
335   for (i = 1; i < cmd->argc; i++) {
336     *((char **) push_array(accepted_envs)) = pstrdup(c->pool, cmd->argv[i]);
337   }
338   c->argv[0] = (void *) accepted_envs;
339 
340   return PR_HANDLED(cmd);
341 }
342 
343 /* usage: SFTPAuthMethods method-list1 ... method-listN */
set_sftpauthmeths(cmd_rec * cmd)344 MODRET set_sftpauthmeths(cmd_rec *cmd) {
345   register unsigned int i;
346   config_rec *c;
347   array_header *auth_chains;
348 
349   if (cmd->argc < 2) {
350     CONF_ERROR(cmd, "Wrong number of parameters");
351   }
352 
353   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
354 
355   c = add_config_param(cmd->argv[0], 1, NULL);
356   auth_chains = make_array(c->pool, 0, sizeof(struct sftp_auth_chain *));
357 
358   for (i = 1; i < cmd->argc; i++) {
359     array_header *method_names;
360     register unsigned int j;
361     struct sftp_auth_chain *auth_chain;
362 
363     method_names = sftp_auth_chain_parse_method_chain(cmd->tmp_pool,
364       cmd->argv[i]);
365     if (method_names == NULL) {
366       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
367         "invalid authentication parameter: ", (char *) cmd->argv[i], NULL));
368     }
369 
370     auth_chain = sftp_auth_chain_alloc(c->pool);
371     for (j = 0; j < method_names->nelts; j++) {
372       int res;
373       char *name;
374       unsigned int method_id = 0;
375       const char *method_name = NULL, *submethod_name = NULL;
376 
377       name = ((char **) method_names->elts)[j];
378 
379       res = sftp_auth_chain_parse_method(c->pool, name, &method_id,
380         &method_name, &submethod_name);
381       if (res < 0) {
382         /* Make for a slightly better/more informative error message. */
383         if (method_id == SFTP_AUTH_FL_METH_KBDINT) {
384           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
385             "unsupported authentication method '", name,
386             "': No drivers loaded", NULL));
387 
388         } else {
389           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
390             "unsupported authentication method '", name, "': ",
391             strerror(errno), NULL));
392         }
393       }
394 
395       sftp_auth_chain_add_method(auth_chain, method_id, method_name,
396         submethod_name);
397     }
398 
399     if (sftp_auth_chain_isvalid(auth_chain) < 0) {
400       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
401         "unsupportable chain of authentication methods '",
402         (char *) cmd->argv[i], "': ", strerror(errno), NULL));
403     }
404 
405     *((struct sftp_auth_chain **) push_array(auth_chains)) = auth_chain;
406   }
407 
408   c->argv[0] = auth_chains;
409   return PR_HANDLED(cmd);
410 }
411 
412 /* usage: SFTPAuthorized{Host,User}Keys store1 ... */
set_sftpauthorizedkeys(cmd_rec * cmd)413 MODRET set_sftpauthorizedkeys(cmd_rec *cmd) {
414   register unsigned int i;
415   int requested_key_type = 0;
416   config_rec *c;
417 
418   if (cmd->argc < 2) {
419     CONF_ERROR(cmd, "wrong number of parameters");
420   }
421 
422   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
423 
424   if (strncasecmp(cmd->argv[0], "SFTPAuthorizedHostKeys", 23) == 0) {
425     requested_key_type = SFTP_SSH2_HOST_KEY_STORE;
426 
427   } else if (strncasecmp(cmd->argv[0], "SFTPAuthorizedUserKeys", 23) == 0) {
428     requested_key_type = SFTP_SSH2_USER_KEY_STORE;
429   }
430 
431   for (i = 1; i < cmd->argc; i++) {
432     char *ptr;
433 
434     /* Separate the parameter into its separate store-type:store-info pieces. */
435     ptr = strchr(cmd->argv[i], ':');
436     if (ptr == NULL) {
437       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "badly formatted parameter: '",
438         (char *) cmd->argv[i], "'", NULL));
439     }
440     *ptr = '\0';
441 
442     /* Verify that the requested store type has been registered, and supports
443      * the type of keystore requested (host or user key).
444      */
445     if (sftp_keystore_supports_store(cmd->argv[i], requested_key_type) < 0) {
446       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unsupported key store: '",
447         (char *) cmd->argv[i], "'", NULL));
448     }
449 
450     *ptr = ':';
451   }
452 
453   c = add_config_param(cmd->argv[0], 0);
454   c->argc = cmd->argc-1;
455   c->argv = pcalloc(c->pool, c->argc * (sizeof(char *)));
456   for (i = 1; i < cmd->argc; i++) {
457     c->argv[i-1] = pstrdup(c->pool, cmd->argv[i]);
458   }
459 
460   return PR_HANDLED(cmd);
461 }
462 
463 /* usage: SFTPCiphers list */
set_sftpciphers(cmd_rec * cmd)464 MODRET set_sftpciphers(cmd_rec *cmd) {
465   register unsigned int i;
466   config_rec *c;
467 
468   if (cmd->argc < 2) {
469     CONF_ERROR(cmd, "Wrong number of parameters");
470   }
471 
472   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
473 
474   for (i = 1; i < cmd->argc; i++) {
475     if (sftp_crypto_get_cipher(cmd->argv[i], NULL, NULL) == NULL) {
476       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
477         "unsupported cipher algorithm: ", (char *) cmd->argv[i], NULL));
478     }
479   }
480 
481   c = add_config_param(cmd->argv[0], cmd->argc-1, NULL);
482   for (i = 1; i < cmd->argc; i++) {
483     c->argv[i-1] = pstrdup(c->pool, cmd->argv[i]);
484   }
485 
486   return PR_HANDLED(cmd);
487 }
488 
489 /* usage: SFTPClientAlive count interval */
set_sftpclientalive(cmd_rec * cmd)490 MODRET set_sftpclientalive(cmd_rec *cmd) {
491   int count, interval;
492   config_rec *c;
493 
494   CHECK_ARGS(cmd, 2);
495   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
496 
497   count = atoi(cmd->argv[1]);
498   if (count < 0) {
499     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "max count '",
500       (char *) cmd->argv[1], "' must be equal to or greater than zero", NULL));
501   }
502 
503   interval = atoi(cmd->argv[2]);
504   if (interval < 0) {
505     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "interval '", (char *) cmd->argv[2],
506       "' must be equal to or greater than zero", NULL));
507   }
508 
509   c = add_config_param(cmd->argv[0], 2, NULL, NULL);
510   c->argv[0] = palloc(c->pool, sizeof(unsigned int));
511   *((unsigned int *) c->argv[0]) = count;
512   c->argv[1] = palloc(c->pool, sizeof(unsigned int));
513   *((unsigned int *) c->argv[1]) = interval;
514 
515   return PR_HANDLED(cmd);
516 }
517 
518 /* usage: SFTPClientMatch pattern key1 val1 ... */
set_sftpclientmatch(cmd_rec * cmd)519 MODRET set_sftpclientmatch(cmd_rec *cmd) {
520 #ifdef PR_USE_REGEX
521   register unsigned int i;
522   config_rec *c;
523   pr_table_t *tab;
524   pr_regex_t *pre;
525   int res;
526 
527   if (cmd->argc < 4) {
528     CONF_ERROR(cmd, "Wrong number of parameters");
529 
530   } else {
531     int npairs;
532 
533     /* Make sure we have an even number of args for the key/value pairs. */
534 
535     npairs = cmd->argc - 2;
536     if (npairs % 2 != 0) {
537       CONF_ERROR(cmd, "Wrong number of parameters");
538     }
539   }
540 
541   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
542 
543   pre = pr_regexp_alloc(&sftp_module);
544 
545   res = pr_regexp_compile(pre, cmd->argv[1], REG_EXTENDED|REG_NOSUB);
546   if (res != 0) {
547     char errstr[200];
548 
549     memset(errstr, '\0', sizeof(errstr));
550     pr_regexp_error(res, pre, errstr, sizeof(errstr));
551     pr_regexp_free(NULL, pre);
552 
553     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", (char *) cmd->argv[1],
554       "' failed regex compilation: ", errstr, NULL));
555   }
556 
557   c = add_config_param(cmd->argv[0], 3, NULL, NULL, NULL);
558   c->argv[0] = pstrdup(c->pool, cmd->argv[1]);
559   c->argv[1] = pre;
560 
561   tab = pr_table_alloc(c->pool, 0);
562 
563   c->argv[2] = tab;
564 
565   for (i = 2; i < cmd->argc; i++) {
566     if (strncmp(cmd->argv[i], "channelWindowSize", 18) == 0) {
567       off_t window_size;
568       void *value;
569       char *arg, units[3];
570       size_t arglen;
571 
572       arg = pstrdup(cmd->tmp_pool, cmd->argv[i+1]);
573       arglen = strlen(arg);
574 
575       memset(units, '\0', sizeof(units));
576 
577       if (arglen >= 3) {
578         /* Look for any possible "GB", "MB", "KB", "B" suffixes. */
579 
580         if ((arg[arglen-2] == 'G' || arg[arglen-2] == 'g') &&
581             (arg[arglen-1] == 'B' || arg[arglen-1] == 'b')) {
582           units[0] = 'G';
583           units[1] = 'B';
584           arg[arglen-2] = '\0';
585           arg[arglen-1] = '\0';
586           arglen -= 2;
587 
588         } else if ((arg[arglen-2] == 'M' || arg[arglen-2] == 'm') &&
589                    (arg[arglen-1] == 'B' || arg[arglen-1] == 'b')) {
590           units[0] = 'M';
591           units[1] = 'B';
592           arg[arglen-2] = '\0';
593           arg[arglen-1] = '\0';
594           arglen -= 2;
595 
596         } else if ((arg[arglen-2] == 'K' || arg[arglen-2] == 'k') &&
597                    (arg[arglen-1] == 'B' || arg[arglen-1] == 'b')) {
598           units[0] = 'K';
599           units[1] = 'B';
600           arg[arglen-2] = '\0';
601           arg[arglen-1] = '\0';
602           arglen -= 2;
603 
604         } else if (arg[arglen-1] == 'B' || arg[arglen-1] == 'b') {
605           units[0] = 'B';
606           arg[arglen-1] = '\0';
607           arglen--;
608         }
609 
610       } else if (arglen >= 2) {
611         /* Look for any possible "B" suffix. */
612         if (arg[arglen-1] == 'B' || arg[arglen-1] == 'b') {
613           units[0] = 'B';
614           arg[arglen-1] = '\0';
615           arglen--;
616         }
617       }
618 
619       if (pr_str_get_nbytes(arg, units, &window_size) < 0) {
620         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
621           "error parsing 'channelWindowSize' value ", cmd->argv[i+1], ": ",
622           strerror(errno), NULL));
623       }
624 
625       value = palloc(c->pool, sizeof(uint32_t));
626       *((uint32_t *) value) = (uint32_t) window_size;
627 
628       if (pr_table_add(tab, pstrdup(c->pool, "channelWindowSize"), value,
629           sizeof(uint32_t)) < 0) {
630         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
631           "error storing 'channelWindowSize' value: ", strerror(errno), NULL));
632       }
633 
634       /* Don't forget to advance i past the value. */
635       i++;
636 
637     } else if (strncmp(cmd->argv[i], "channelPacketSize", 18) == 0) {
638       off_t packet_size;
639       void *value;
640       char *arg, units[3];
641       size_t arglen;
642 
643       arg = pstrdup(cmd->tmp_pool, cmd->argv[i+1]);
644       arglen = strlen(arg);
645 
646       memset(units, '\0', sizeof(units));
647 
648       if (arglen >= 3) {
649         /* Look for any possible "GB", "MB", "KB", "B" suffixes. */
650 
651         if ((arg[arglen-2] == 'G' || arg[arglen-2] == 'g') &&
652             (arg[arglen-1] == 'B' || arg[arglen-1] == 'b')) {
653           units[0] = 'G';
654           units[1] = 'B';
655           arg[arglen-2] = '\0';
656           arg[arglen-1] = '\0';
657           arglen -= 2;
658 
659         } else if ((arg[arglen-2] == 'M' || arg[arglen-2] == 'm') &&
660                    (arg[arglen-1] == 'B' || arg[arglen-1] == 'b')) {
661           units[0] = 'M';
662           units[1] = 'B';
663           arg[arglen-2] = '\0';
664           arg[arglen-1] = '\0';
665           arglen -= 2;
666 
667         } else if ((arg[arglen-2] == 'K' || arg[arglen-2] == 'k') &&
668                    (arg[arglen-1] == 'B' || arg[arglen-1] == 'b')) {
669           units[0] = 'K';
670           units[1] = 'B';
671           arg[arglen-2] = '\0';
672           arg[arglen-1] = '\0';
673           arglen -= 2;
674 
675         } else if (arg[arglen-1] == 'B' || arg[arglen-1] == 'b') {
676           units[0] = 'B';
677           arg[arglen-1] = '\0';
678           arglen--;
679         }
680 
681       } else if (arglen >= 2) {
682         /* Look for any possible "B" suffix. */
683         if (arg[arglen-1] == 'B' || arg[arglen-1] == 'b') {
684           units[0] = 'B';
685           arg[arglen-1] = '\0';
686           arglen--;
687         }
688       }
689 
690       if (pr_str_get_nbytes(arg, units, &packet_size) < 0) {
691         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
692           "error parsing 'channelPacketSize' value ", cmd->argv[i+1], ": ",
693           strerror(errno), NULL));
694       }
695 
696       if (packet_size > SFTP_MAX_PACKET_LEN) {
697         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
698           "'channelPacketSize' value ", cmd->argv[i+1], " too large, must be "
699           "less than 35000B", NULL));
700       }
701 
702       value = palloc(c->pool, sizeof(uint32_t));
703       *((uint32_t *) value) = (uint32_t) packet_size;
704 
705       if (pr_table_add(tab, pstrdup(c->pool, "channelPacketSize"), value,
706           sizeof(uint32_t)) < 0) {
707         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
708           "error storing 'channelPacketSize' value: ", strerror(errno), NULL));
709       }
710 
711       /* Don't forget to advance i past the value. */
712       i++;
713 
714     } else if (strncmp(cmd->argv[i], "pessimisticNewkeys", 19) == 0) {
715       int pessimistic_newkeys;
716       void *value;
717 
718       pessimistic_newkeys = get_boolean(cmd, i+1);
719       if (pessimistic_newkeys == -1) {
720         CONF_ERROR(cmd, "expected Boolean parameter");
721       }
722 
723       value = palloc(c->pool, sizeof(int));
724       *((int *) value) = pessimistic_newkeys;
725 
726       if (pr_table_add(tab, pstrdup(c->pool, "pessimisticNewkeys"), value,
727           sizeof(int)) < 0) {
728         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
729           "error storing 'pessimisticNewkeys' value: ", strerror(errno), NULL));
730       }
731 
732       /* Don't forget to advance i past the value. */
733       i++;
734 
735     } else if (strncmp(cmd->argv[i], "sftpProtocolVersion", 20) == 0) {
736       void *min_value, *max_value;
737       char *ptr = NULL;
738 
739       /* Check for a range of values. */
740       ptr = strchr(cmd->argv[i+1], '-');
741 
742       if (ptr == NULL) {
743         long protocol_version;
744 
745         /* Just a single value. */
746 
747         protocol_version = strtol(cmd->argv[i+1], &ptr, 10);
748         if (ptr && *ptr) {
749           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
750             "badly formatted 'sftpProtocolVersion' value: ", cmd->argv[i+1],
751             NULL));
752         }
753 
754         if (protocol_version < 1 ||
755             protocol_version > 6) {
756           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
757             "'sftpProtocolVersion' value ", cmd->argv[i+1],
758             " must be between 1 and 6: ", strerror(errno), NULL));
759         }
760 
761         min_value = palloc(c->pool, sizeof(unsigned int));
762         *((unsigned int *) min_value) = (unsigned int) protocol_version;
763 
764         max_value = palloc(c->pool, sizeof(unsigned int));
765         *((unsigned int *) max_value) = (unsigned int) protocol_version;
766 
767       } else {
768         long min_version, max_version;
769         char *tmp = NULL;
770 
771         /* We have a range of values. */
772 
773         *ptr = '\0';
774         min_version = strtol(cmd->argv[i+1], &tmp, 10);
775 
776         if (tmp && *tmp) {
777           *ptr = '-';
778           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
779             "badly formatted 'sftpProtocolVersion' value: ", cmd->argv[i+1],
780             NULL));
781         }
782         *ptr = '-';
783 
784         if (min_version < 1 ||
785             min_version > 6) {
786           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
787             "'sftpProtocolVersion' value ", cmd->argv[i+1],
788             " must be between 1 and 6: ", strerror(errno), NULL));
789         }
790 
791         min_value = palloc(c->pool, sizeof(unsigned int));
792         *((unsigned int *) min_value) = (unsigned int) min_version;
793 
794         *ptr = '\0';
795         tmp = NULL;
796         max_version = strtol(ptr + 1, &tmp, 10);
797 
798         if (tmp && *tmp) {
799           *ptr = '-';
800           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
801             "badly formatted 'sftpProtocolVersion' value: ", cmd->argv[i+1],
802             NULL));
803         }
804         *ptr = '-';
805 
806         if (max_version < 1 ||
807             max_version > 6) {
808           CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
809             "'sftpProtocolVersion' value ", cmd->argv[i+1],
810             " must be between 1 and 6: ", strerror(errno), NULL));
811         }
812 
813         max_value = palloc(c->pool, sizeof(unsigned int));
814         *((unsigned int *) max_value) = (unsigned int) max_version;
815       }
816 
817       if (pr_table_add(tab, pstrdup(c->pool, "sftpMinProtocolVersion"),
818           min_value, sizeof(unsigned int)) < 0) {
819         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
820           "error storing 'sftpProtocolVersion' value: ", strerror(errno),
821           NULL));
822       }
823 
824       if (pr_table_add(tab, pstrdup(c->pool, "sftpMaxProtocolVersion"),
825           max_value, sizeof(unsigned int)) < 0) {
826         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
827           "error storing 'sftpProtocolVersion' value: ", strerror(errno),
828           NULL));
829       }
830 
831       /* Don't forget to advance i past the value. */
832       i++;
833 
834     } else if (strncmp(cmd->argv[i], "sftpUTF8ProtocolVersion", 24) == 0) {
835 #ifdef PR_USE_NLS
836       char *ptr = NULL;
837       void *value;
838       long protocol_version;
839 
840       protocol_version = strtol(cmd->argv[i+1], &ptr, 10);
841       if (ptr && *ptr) {
842         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
843           "badly formatted 'sftpUTF8ProtocolVersion' value: ", cmd->argv[i+1],
844           NULL));
845       }
846 
847       if (protocol_version < 1 ||
848           protocol_version > 6) {
849         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
850           "'sftpUTF8ProtocolVersion' value ", cmd->argv[i+1], NULL));
851       }
852 
853       value = palloc(c->pool, sizeof(unsigned int));
854       *((unsigned int *) value) = (unsigned int) protocol_version;
855 
856       if (pr_table_add(tab, pstrdup(c->pool, "sftpUTF8ProtocolVersion"),
857           value, sizeof(unsigned int)) < 0) {
858         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
859           "error storing 'sftpUTF8ProtocolVersion' value: ", strerror(errno),
860           NULL));
861       }
862 
863       /* Don't forget to advance i past the value. */
864       i++;
865 #else
866       CONF_ERROR(cmd, "'sftpUTF8ProtocolVersion' requires NLS support (--enable-nls)");
867 #endif /* PR_USE_NLS */
868     } else {
869       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown SFTPClientMatch key: '",
870         cmd->argv[i], "'", NULL));
871     }
872   }
873 
874   return PR_HANDLED(cmd);
875 
876 #else /* no regular expression support at the moment */
877   CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "The ", cmd->argv[0],
878     " directive cannot be used on this system, as you do not have POSIX "
879     "compliant regex support", NULL));
880 #endif
881 }
882 
883 /* usage: SFTPCompression on|off|delayed */
set_sftpcompression(cmd_rec * cmd)884 MODRET set_sftpcompression(cmd_rec *cmd) {
885   config_rec *c;
886   int bool;
887 
888   if (cmd->argc != 2) {
889     CONF_ERROR(cmd, "Wrong number of parameters");
890   }
891 
892   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
893 
894 #ifdef HAVE_ZLIB_H
895   bool = get_boolean(cmd, 1);
896   if (bool == -1) {
897     if (strncasecmp(cmd->argv[1], "delayed", 8) != 0) {
898       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
899         "unknown compression setting: ", cmd->argv[1], NULL));
900     }
901 
902     bool = 2;
903   }
904 #else
905   pr_log_debug(DEBUG0, MOD_SFTP_VERSION ": platform lacks zlib support, ignoring SFTPCompression");
906   bool = 0;
907 #endif /* !HAVE_ZLIB_H */
908 
909   c = add_config_param(cmd->argv[0], 1, NULL);
910   c->argv[0] = pcalloc(c->pool, sizeof(int));
911   *((int *) c->argv[0]) = bool;
912 
913   return PR_HANDLED(cmd);
914 }
915 
916 /* usage: SFTPCryptoDevice engine|"ALL" */
set_sftpcryptodevice(cmd_rec * cmd)917 MODRET set_sftpcryptodevice(cmd_rec *cmd) {
918 #if OPENSSL_VERSION_NUMBER > 0x000907000L
919   CHECK_ARGS(cmd, 1);
920   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
921 
922   (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
923   return PR_HANDLED(cmd);
924 
925 #else /* OpenSSL is too old for ENGINE support */
926   CONF_ERROR(cmd, "unsupportable (OpenSSL version is too old");
927 #endif
928 }
929 
930 /* usage: SFTPDHParamFile path */
set_sftpdhparamfile(cmd_rec * cmd)931 MODRET set_sftpdhparamfile(cmd_rec *cmd) {
932   CHECK_ARGS(cmd, 1);
933   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
934 
935   if (pr_fs_valid_path(cmd->argv[1]) < 0) {
936     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
937       "unable to use '", cmd->argv[1], "'", NULL));
938   }
939 
940   (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
941   return PR_HANDLED(cmd);
942 }
943 
944 /* usage: SFTPDigests list */
set_sftpdigests(cmd_rec * cmd)945 MODRET set_sftpdigests(cmd_rec *cmd) {
946   register unsigned int i;
947   config_rec *c;
948 
949   if (cmd->argc < 2) {
950     CONF_ERROR(cmd, "Wrong number of parameters");
951   }
952 
953   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
954 
955   for (i = 1; i < cmd->argc; i++) {
956     if (sftp_crypto_get_digest(cmd->argv[i], NULL) == NULL) {
957       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
958         "unsupported digest algorithm: ", cmd->argv[i], NULL));
959     }
960   }
961 
962   c = add_config_param(cmd->argv[0], cmd->argc-1, NULL);
963   for (i = 1; i < cmd->argc; i++) {
964     c->argv[i-1] = pstrdup(c->pool, cmd->argv[i]);
965   }
966 
967   return PR_HANDLED(cmd);
968 }
969 
970 /* usage: SFTPDisplayBanner path */
set_sftpdisplaybanner(cmd_rec * cmd)971 MODRET set_sftpdisplaybanner(cmd_rec *cmd) {
972   CHECK_ARGS(cmd, 1);
973   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
974 
975   add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
976   return PR_HANDLED(cmd);
977 }
978 
979 /* usage: SFTPEngine on|off */
set_sftpengine(cmd_rec * cmd)980 MODRET set_sftpengine(cmd_rec *cmd) {
981   int bool = 1;
982   config_rec *c;
983 
984   CHECK_ARGS(cmd, 1);
985   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
986 
987   bool = get_boolean(cmd, 1);
988   if (bool == -1)
989     CONF_ERROR(cmd, "expected Boolean parameter");
990 
991   c = add_config_param(cmd->argv[0], 1, NULL);
992   c->argv[0] = pcalloc(c->pool, sizeof(int));
993   *((int *) c->argv[0]) = bool;
994 
995   return PR_HANDLED(cmd);
996 }
997 
998 /* usage: SFTPExtensions ext1 ... extN */
set_sftpextensions(cmd_rec * cmd)999 MODRET set_sftpextensions(cmd_rec *cmd) {
1000   register unsigned int i;
1001   config_rec *c;
1002   unsigned long ext_flags = SFTP_FXP_EXT_DEFAULT;
1003 
1004   if (cmd->argc < 2) {
1005     CONF_ERROR(cmd, "wrong number of parameters");
1006   }
1007 
1008   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1009 
1010   for (i = 1; i < cmd->argc; i++) {
1011     char action, *ext;
1012 
1013     ext = cmd->argv[i];
1014     action = *ext;
1015 
1016     if (action != '-' &&
1017         action != '+') {
1018       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "bad option: '", ext, "'",
1019         NULL));
1020     }
1021 
1022     ext++;
1023 
1024     if (strncasecmp(ext, "checkFile", 10) == 0) {
1025       switch (action) {
1026         case '-':
1027           ext_flags &= ~SFTP_FXP_EXT_CHECK_FILE;
1028           break;
1029 
1030         case '+':
1031           ext_flags |= SFTP_FXP_EXT_CHECK_FILE;
1032           break;
1033       }
1034 
1035     } else if (strncasecmp(ext, "copyFile", 9) == 0) {
1036       switch (action) {
1037         case '-':
1038           ext_flags &= ~SFTP_FXP_EXT_COPY_FILE;
1039           break;
1040 
1041         case '+':
1042           ext_flags |= SFTP_FXP_EXT_COPY_FILE;
1043           break;
1044       }
1045 
1046     } else if (strncasecmp(ext, "fsync", 6) == 0) {
1047       switch (action) {
1048         case '-':
1049           ext_flags &= ~SFTP_FXP_EXT_FSYNC;
1050           break;
1051 
1052         case '+':
1053           ext_flags |= SFTP_FXP_EXT_FSYNC;
1054           break;
1055       }
1056 
1057     } else if (strncasecmp(ext, "vendorID", 9) == 0) {
1058       switch (action) {
1059         case '-':
1060           ext_flags &= ~SFTP_FXP_EXT_VENDOR_ID;
1061           break;
1062 
1063         case '+':
1064           ext_flags |= SFTP_FXP_EXT_VENDOR_ID;
1065           break;
1066       }
1067 
1068     } else if (strncasecmp(ext, "versionSelect", 14) == 0) {
1069       switch (action) {
1070         case '-':
1071           ext_flags &= ~SFTP_FXP_EXT_VERSION_SELECT;
1072           break;
1073 
1074         case '+':
1075           ext_flags |= SFTP_FXP_EXT_VERSION_SELECT;
1076           break;
1077       }
1078 
1079     } else if (strncasecmp(ext, "posixRename", 12) == 0) {
1080       switch (action) {
1081         case '-':
1082           ext_flags &= ~SFTP_FXP_EXT_POSIX_RENAME;
1083           break;
1084 
1085         case '+':
1086           ext_flags |= SFTP_FXP_EXT_POSIX_RENAME;
1087           break;
1088       }
1089 
1090     } else if (strncasecmp(ext, "spaceAvailable", 15) == 0) {
1091 #ifdef HAVE_SYS_STATVFS_H
1092       switch (action) {
1093         case '-':
1094           ext_flags &= ~SFTP_FXP_EXT_SPACE_AVAIL;
1095           break;
1096 
1097         case '+':
1098           ext_flags |= SFTP_FXP_EXT_SPACE_AVAIL;
1099           break;
1100       }
1101 #else
1102       pr_log_debug(DEBUG0, "%s: spaceAvailable extension not supported "
1103         "on this system; requires statvfs(3) support", cmd->argv[0]);
1104 #endif /* !HAVE_SYS_STATVFS_H */
1105 
1106 
1107     } else if (strncasecmp(ext, "statvfs", 8) == 0) {
1108 #ifdef HAVE_SYS_STATVFS_H
1109       switch (action) {
1110         case '-':
1111           ext_flags &= ~SFTP_FXP_EXT_STATVFS;
1112           break;
1113 
1114         case '+':
1115           ext_flags |= SFTP_FXP_EXT_STATVFS;
1116           break;
1117       }
1118 #else
1119       pr_log_debug(DEBUG0, "%s: statvfs@openssh.com extension not supported "
1120         "on this system; requires statvfs(3) support", cmd->argv[0]);
1121 #endif /* !HAVE_SYS_STATVFS_H */
1122 
1123     } else if (strncasecmp(ext, "hardlink", 9) == 0) {
1124       switch (action) {
1125         case '-':
1126           ext_flags &= ~SFTP_FXP_EXT_HARDLINK;
1127           break;
1128 
1129         case '+':
1130           ext_flags |= SFTP_FXP_EXT_HARDLINK;
1131           break;
1132       }
1133 
1134     } else if (strncasecmp(ext, "xattr", 8) == 0) {
1135 #ifdef HAVE_SYS_XATTR_H
1136       switch (action) {
1137         case '-':
1138           ext_flags &= ~SFTP_FXP_EXT_XATTR;
1139           break;
1140 
1141         case '+':
1142           ext_flags |= SFTP_FXP_EXT_XATTR;
1143           break;
1144       }
1145 #else
1146       pr_log_debug(DEBUG0, "%s: xattr@proftpd.org extension not supported "
1147         "on this system; requires extended attribute support",
1148         (char *) cmd->argv[0]);
1149 #endif /* HAVE_SYS_XATTR_H */
1150 
1151     } else {
1152       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unknown extension: '",
1153         ext, "'", NULL));
1154     }
1155   }
1156 
1157   c = add_config_param(cmd->argv[0], 1, NULL);
1158   c->argv[0] = palloc(c->pool, sizeof(unsigned long));
1159   *((unsigned long *) c->argv[0]) = ext_flags;
1160 
1161   return PR_HANDLED(cmd);
1162 }
1163 
1164 /* usage: SFTPHostKey path|"agent:/..."|"NoRSA"|"NoDSA"|"NoECDSA"|"NoED25519" */
set_sftphostkey(cmd_rec * cmd)1165 MODRET set_sftphostkey(cmd_rec *cmd) {
1166   struct stat st;
1167   int flags = 0;
1168   config_rec *c;
1169   const char *path = NULL;
1170 
1171   CHECK_ARGS(cmd, 1);
1172   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1173 
1174   if (strncasecmp(cmd->argv[1], "NoRSA", 6) == 0) {
1175     flags |= SFTP_HOSTKEY_FL_CLEAR_RSA_KEY;
1176 
1177   } else if (strncasecmp(cmd->argv[1], "NoDSA", 6) == 0) {
1178     flags |= SFTP_HOSTKEY_FL_CLEAR_DSA_KEY;
1179 
1180   } else if (strncasecmp(cmd->argv[1], "NoECDSA", 8) == 0) {
1181     flags |= SFTP_HOSTKEY_FL_CLEAR_ECDSA_KEY;
1182 
1183   } else if (strncasecmp(cmd->argv[1], "NoED25519", 10) == 0) {
1184     flags |= SFTP_HOSTKEY_FL_CLEAR_ED25519_KEY;
1185   }
1186 
1187   if (strncmp(cmd->argv[1], "agent:", 6) != 0 &&
1188       flags == 0) {
1189     int res, xerrno;
1190 
1191     path = cmd->argv[1];
1192     if (*path != '/') {
1193       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "must be an absolute path: ",
1194         path, NULL));
1195     }
1196 
1197     PRIVS_ROOT
1198     res = stat(path, &st);
1199     xerrno = errno;
1200     PRIVS_RELINQUISH
1201 
1202     if (res < 0) {
1203       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to check '", path,
1204         "': ", strerror(xerrno), NULL));
1205     }
1206 
1207     if ((st.st_mode & S_IRWXG) ||
1208         (st.st_mode & S_IRWXO)) {
1209       int insecure_hostkey_perms = FALSE;
1210 
1211       /* Check for the InsecureHostKeyPerms SFTPOption. */
1212       c = find_config(cmd->server->conf, CONF_PARAM, "SFTPOptions", FALSE);
1213       while (c != NULL) {
1214         unsigned long opts;
1215 
1216         pr_signals_handle();
1217 
1218         opts = *((unsigned long *) c->argv[0]);
1219         if (opts & SFTP_OPT_INSECURE_HOSTKEY_PERMS) {
1220           insecure_hostkey_perms = TRUE;
1221           break;
1222         }
1223 
1224         c = find_config_next(c, c->next, CONF_PARAM, "SFTPOptions", FALSE);
1225       }
1226 
1227       if (insecure_hostkey_perms) {
1228         pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION ": unable to use '%s' "
1229           "as host key, as it is group- or world-accessible", path);
1230 
1231       } else {
1232         CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to use '", path,
1233           "' as host key, as it is group- or world-accessible", NULL));
1234       }
1235     }
1236   }
1237 
1238   c = add_config_param_str(cmd->argv[0], 2, NULL, NULL);
1239   c->argv[0] = pstrdup(c->pool, path);
1240   c->argv[1] = palloc(c->pool, sizeof(int));
1241   *((int *) c->argv[1]) = flags;
1242   return PR_HANDLED(cmd);
1243 }
1244 
1245 /* usage: SFTPKeyBlacklist "none"|path */
set_sftpkeyblacklist(cmd_rec * cmd)1246 MODRET set_sftpkeyblacklist(cmd_rec *cmd) {
1247   CHECK_ARGS(cmd, 1);
1248   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1249 
1250   if (strncasecmp(cmd->argv[1], "none", 5) != 0) {
1251     if (pr_fs_valid_path(cmd->argv[1]) < 0) {
1252       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "path '", cmd->argv[1],
1253         "' not an absolute path", NULL));
1254     }
1255 
1256     if (!exists2(cmd->tmp_pool, cmd->argv[1])) {
1257       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "path '", cmd->argv[1],
1258         "' not found", NULL));
1259     }
1260   }
1261 
1262   add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
1263   return PR_HANDLED(cmd);
1264 }
1265 
1266 /* usage: SFTPKeyExchanges list */
set_sftpkeyexchanges(cmd_rec * cmd)1267 MODRET set_sftpkeyexchanges(cmd_rec *cmd) {
1268   register unsigned int i;
1269   config_rec *c;
1270   char *exchanges = "";
1271 
1272   if (cmd->argc < 2) {
1273     CONF_ERROR(cmd, "Wrong number of parameters");
1274   }
1275 
1276   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1277 
1278   for (i = 1; i < cmd->argc; i++) {
1279     if (strncmp(cmd->argv[i], "diffie-hellman-group1-sha1", 27) != 0 &&
1280         strncmp(cmd->argv[i], "diffie-hellman-group14-sha1", 28) != 0 &&
1281 #if (OPENSSL_VERSION_NUMBER > 0x000907000L && defined(OPENSSL_FIPS)) || \
1282     (OPENSSL_VERSION_NUMBER > 0x000908000L)
1283         strncmp(cmd->argv[i], "diffie-hellman-group14-sha256", 30) != 0 &&
1284         strncmp(cmd->argv[i], "diffie-hellman-group16-sha512", 30) != 0 &&
1285         strncmp(cmd->argv[i], "diffie-hellman-group18-sha512", 30) != 0 &&
1286         strncmp(cmd->argv[i], "diffie-hellman-group-exchange-sha256", 37) != 0 &&
1287 #endif
1288         strncmp(cmd->argv[i], "diffie-hellman-group-exchange-sha1", 35) != 0 &&
1289 #ifdef PR_USE_OPENSSL_ECC
1290         strncmp(cmd->argv[i], "ecdh-sha2-nistp256", 19) != 0 &&
1291         strncmp(cmd->argv[i], "ecdh-sha2-nistp384", 19) != 0 &&
1292         strncmp(cmd->argv[i], "ecdh-sha2-nistp521", 19) != 0 &&
1293 #endif /* PR_USE_OPENSSL_ECC */
1294 #if defined(HAVE_SODIUM_H) && defined(HAVE_SHA256_OPENSSL)
1295         strncmp(cmd->argv[i], "curve25519-sha256@libssh.org", 22) != 0 &&
1296 #endif /* HAVE_SODIUM_H and HAVE_SHA256_OPENSSL */
1297         strncmp(cmd->argv[i], "rsa1024-sha1", 13) != 0) {
1298 
1299       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1300         "unsupported key exchange algorithm: ", cmd->argv[i], NULL));
1301     }
1302   }
1303 
1304   c = add_config_param(cmd->argv[0], 1, NULL);
1305 
1306   for (i = 1; i < cmd->argc; i++) {
1307     exchanges = pstrcat(c->pool, exchanges, *exchanges ? "," : "", cmd->argv[i],
1308       NULL);
1309   }
1310   c->argv[0] = exchanges;
1311 
1312   return PR_HANDLED(cmd);
1313 }
1314 
1315 /* usage: SFTPKeyLimits limit1 ... limitN */
set_sftpkeylimits(cmd_rec * cmd)1316 MODRET set_sftpkeylimits(cmd_rec *cmd) {
1317   register unsigned int i;
1318   config_rec *c;
1319 
1320   if (cmd->argc < 3 ||
1321       ((cmd->argc-1) % 2 != 0)) {
1322     CONF_ERROR(cmd, "wrong number of parameters");
1323   }
1324   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1325 
1326   c = add_config_param(cmd->argv[0], 3, NULL, NULL, NULL);
1327 
1328   for (i = 1; i < cmd->argc; i++) {
1329     if (strcasecmp(cmd->argv[i], "MinimumRSASize") == 0) {
1330       int nbits;
1331 
1332       nbits = atoi(cmd->argv[++i]);
1333       if (nbits < 0) {
1334         CONF_ERROR(cmd, "minimum key size must be zero or greater");
1335       }
1336 
1337       c->argv[0] = palloc(c->pool, sizeof(int));
1338       *((int *) c->argv[0]) = nbits;
1339 
1340     } else if (strcasecmp(cmd->argv[i], "MinimumDSASize") == 0) {
1341       int nbits;
1342 
1343       nbits = atoi(cmd->argv[++i]);
1344       if (nbits < 0) {
1345         CONF_ERROR(cmd, "minimum key size must be zero or greater");
1346       }
1347 
1348       c->argv[1] = palloc(c->pool, sizeof(int));
1349       *((int *) c->argv[1]) = nbits;
1350 
1351     } else if (strcasecmp(cmd->argv[i], "MinimumECSize") == 0) {
1352       int nbits;
1353 
1354       nbits = atoi(cmd->argv[++i]);
1355       if (nbits < 0) {
1356         CONF_ERROR(cmd, "minimum key size must be zero or greater");
1357       }
1358 
1359       c->argv[2] = palloc(c->pool, sizeof(int));
1360       *((int *) c->argv[2]) = nbits;
1361 
1362     } else {
1363       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown SFTPKeyLimit '",
1364         cmd->argv[i], "'", NULL));
1365     }
1366   }
1367 
1368   return PR_HANDLED(cmd);
1369 }
1370 
1371 /* usage: SFTPLog path|"none" */
set_sftplog(cmd_rec * cmd)1372 MODRET set_sftplog(cmd_rec *cmd) {
1373   CHECK_ARGS(cmd, 1);
1374   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1375 
1376   (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
1377   return PR_HANDLED(cmd);
1378 }
1379 
1380 /* usage: SFTPMaxChannels max */
set_sftpmaxchannels(cmd_rec * cmd)1381 MODRET set_sftpmaxchannels(cmd_rec *cmd) {
1382   config_rec *c;
1383   unsigned int max;
1384   char *ptr = NULL;
1385 
1386   CHECK_ARGS(cmd, 1);
1387   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1388 
1389   max = strtoul(cmd->argv[1], &ptr, 10);
1390 
1391   if (ptr && *ptr) {
1392     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "maximum channel count '",
1393       cmd->argv[1], "' must be numeric", NULL));
1394   }
1395 
1396   if (max == 0) {
1397     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "maximum channel count '",
1398       cmd->argv[1], "' must be greater than zero", NULL));
1399   }
1400 
1401   c = add_config_param(cmd->argv[0], 1, NULL);
1402   c->argv[0] = palloc(c->pool, sizeof(unsigned int));
1403   *((unsigned int *) c->argv[0]) = max;
1404 
1405   return PR_HANDLED(cmd);
1406 }
1407 
1408 /* usage: SFTPOptions opt1 ... optN */
set_sftpoptions(cmd_rec * cmd)1409 MODRET set_sftpoptions(cmd_rec *cmd) {
1410   register unsigned int i;
1411   config_rec *c;
1412   unsigned long opts = 0UL;
1413 
1414   if (cmd->argc-1 == 0)
1415     CONF_ERROR(cmd, "wrong number of parameters");
1416 
1417   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1418 
1419   c = add_config_param(cmd->argv[0], 1, NULL);
1420 
1421   for (i = 1; i < cmd->argc; i++) {
1422     if (strncmp(cmd->argv[i], "IgnoreSFTPUploadPerms", 22) == 0) {
1423       opts |= SFTP_OPT_IGNORE_SFTP_UPLOAD_PERMS;
1424 
1425     } else if (strncmp(cmd->argv[i], "IgnoreSFTPSetOwners", 19) == 0) {
1426       opts |= SFTP_OPT_IGNORE_SFTP_SET_OWNERS;
1427 
1428     } else if (strncmp(cmd->argv[i], "IgnoreSFTPSetPerms", 19) == 0) {
1429       opts |= SFTP_OPT_IGNORE_SFTP_SET_PERMS;
1430 
1431     } else if (strncmp(cmd->argv[i], "IgnoreSFTPSetTimes", 19) == 0) {
1432       opts |= SFTP_OPT_IGNORE_SFTP_SET_TIMES;
1433 
1434     } else if (strncmp(cmd->argv[i], "IgnoreSCPUploadPerms", 20) == 0) {
1435       opts |= SFTP_OPT_IGNORE_SCP_UPLOAD_PERMS;
1436 
1437     } else if (strncmp(cmd->argv[i], "IgnoreSCPUploadTimes", 20) == 0) {
1438       opts |= SFTP_OPT_IGNORE_SCP_UPLOAD_TIMES;
1439 
1440     } else if (strncmp(cmd->argv[i], "OldProtocolCompat", 18) == 0) {
1441       opts |= SFTP_OPT_OLD_PROTO_COMPAT;
1442 
1443       /* This option also automatically enables PessimisticKexint,
1444        * as per the comments in RFC4253, Section 5.1.
1445        */
1446       opts |= SFTP_OPT_PESSIMISTIC_KEXINIT;
1447 
1448     } else if (strncmp(cmd->argv[i], "PessimisticKexinit", 19) == 0) {
1449       opts |= SFTP_OPT_PESSIMISTIC_KEXINIT;
1450 
1451     } else if (strncmp(cmd->argv[i], "MatchKeySubject", 16) == 0) {
1452       opts |= SFTP_OPT_MATCH_KEY_SUBJECT;
1453 
1454     } else if (strcmp(cmd->argv[i], "AllowInsecureLogin") == 0) {
1455       opts |= SFTP_OPT_ALLOW_INSECURE_LOGIN;
1456 
1457     } else if (strcmp(cmd->argv[i], "InsecureHostKeyPerms") == 0) {
1458       opts |= SFTP_OPT_INSECURE_HOSTKEY_PERMS;
1459 
1460     } else if (strcmp(cmd->argv[i], "AllowWeakDH") == 0) {
1461       opts |= SFTP_OPT_ALLOW_WEAK_DH;
1462 
1463     } else if (strcmp(cmd->argv[i], "IgnoreFIFOs") == 0) {
1464       opts |= SFTP_OPT_IGNORE_FIFOS;
1465 
1466     } else if (strcmp(cmd->argv[i],
1467                "IgnoreSFTPUploadExtendedAttributes") == 0) {
1468       opts |= SFTP_OPT_IGNORE_SFTP_UPLOAD_XATTRS;
1469 
1470     } else if (strcmp(cmd->argv[i], "IgnoreSFTPSetExtendedAttributes") == 0) {
1471       opts |= SFTP_OPT_IGNORE_SFTP_SET_XATTRS;
1472 
1473     } else if (strcmp(cmd->argv[i], "IncludeSFTPTimes") == 0) {
1474       opts |= SFTP_OPT_INCLUDE_SFTP_TIMES;
1475 
1476     } else if (strcmp(cmd->argv[i], "NoExtensionNegotiation") == 0) {
1477       opts |= SFTP_OPT_NO_EXT_INFO;
1478 
1479     } else {
1480       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown SFTPOption '",
1481         cmd->argv[i], "'", NULL));
1482     }
1483   }
1484 
1485   c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
1486   *((unsigned long *) c->argv[0]) = opts;
1487 
1488   return PR_HANDLED(cmd);
1489 }
1490 
1491 /* usage: SFTPPassPhraseProvider path */
set_sftppassphraseprovider(cmd_rec * cmd)1492 MODRET set_sftppassphraseprovider(cmd_rec *cmd) {
1493   struct stat st;
1494   char *path;
1495 
1496   CHECK_ARGS(cmd, 1);
1497   CHECK_CONF(cmd, CONF_ROOT);
1498 
1499   path = cmd->argv[1];
1500 
1501   if (*path != '/') {
1502     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "must be a full path: '", path, "'",
1503       NULL));
1504   }
1505 
1506   if (stat(path, &st) < 0) {
1507     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "error checking '", path, "': ",
1508       strerror(errno), NULL));
1509   }
1510 
1511   if (!S_ISREG(st.st_mode)) {
1512     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to use '", path,
1513       ": Not a regular file", NULL));
1514   }
1515 
1516   add_config_param_str(cmd->argv[0], 1, path);
1517   return PR_HANDLED(cmd);
1518 }
1519 
1520 /* usage: SFTPRekey "none"|"required" [interval bytes [timeout]] */
set_sftprekey(cmd_rec * cmd)1521 MODRET set_sftprekey(cmd_rec *cmd) {
1522   config_rec *c;
1523   int rekey_interval;
1524   unsigned long rekey_mbytes;
1525   char *ptr = NULL;
1526 
1527   if (cmd->argc-1 < 1 || cmd->argc-1 > 4) {
1528     CONF_ERROR(cmd, "wrong number of parameters");
1529   }
1530 
1531   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1532 
1533   if (strncasecmp(cmd->argv[1], "none", 5) == 0) {
1534     c = add_config_param(cmd->argv[0], 1, NULL);
1535     c->argv[0] = pcalloc(c->pool, sizeof(int));
1536     *((int *) c->argv[0]) = FALSE;
1537 
1538     return PR_HANDLED(cmd);
1539   }
1540 
1541   if (strncasecmp(cmd->argv[1], "required", 9) != 0) {
1542     CONF_ERROR(cmd, "expected either 'none' or 'required'");
1543   }
1544 
1545   if (cmd->argc-1 == 4) {
1546     /* The admin specified a rekey timeout as well.  Nice. */
1547     c = add_config_param(cmd->argv[0], 4, NULL, NULL, NULL, NULL);
1548 
1549   } else {
1550     /* The admin did not specify rekey timeout as well.  Oh well. */
1551     c = add_config_param(cmd->argv[0], 3, NULL, NULL, NULL);
1552   }
1553 
1554   c->argv[0] = pcalloc(c->pool, sizeof(int));
1555   *((int *) c->argv[0]) = TRUE;
1556 
1557   if (cmd->argc-1 >= 2) {
1558     rekey_interval = atoi(cmd->argv[2]);
1559 
1560   } else {
1561     /* Default: one hour. */
1562     rekey_interval = 3600;
1563   }
1564 
1565   if (rekey_interval > 0) {
1566     c->argv[1] = pcalloc(c->pool, sizeof(int));
1567     *((int *) c->argv[1]) = rekey_interval;
1568 
1569   } else {
1570     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "rekey interval '", cmd->argv[2],
1571       "' must be greater than zero", NULL));
1572   }
1573 
1574   if (cmd->argc-1 >= 3) {
1575     rekey_mbytes = strtoul(cmd->argv[3], &ptr, 10);
1576     if (ptr && *ptr) {
1577       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "rekey MB '", cmd->argv[3],
1578         "' must be numeric", NULL));
1579     }
1580 
1581   } else {
1582     /* Default: 2 GB */
1583     rekey_mbytes = (2 * 1024);
1584   }
1585 
1586   c->argv[2] = pcalloc(c->pool, sizeof(off_t));
1587   *((off_t *) c->argv[2]) = (off_t) rekey_mbytes * 1024 * 1024;
1588 
1589   if (cmd->argc-1 == 4) {
1590     int rekey_timeout;
1591 
1592     rekey_timeout = atoi(cmd->argv[4]);
1593     if (rekey_timeout > 0) {
1594       c->argv[3] = pcalloc(c->pool, sizeof(int));
1595       *((int *) c->argv[3]) = rekey_timeout;
1596 
1597     } else {
1598       CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "rekey timeout '", cmd->argv[4],
1599         "' must be greater than zero", NULL));
1600     }
1601   }
1602 
1603   return PR_HANDLED(cmd);
1604 }
1605 
1606 /* usage: SFTPTrafficPolicy policy */
set_sftptrafficpolicy(cmd_rec * cmd)1607 MODRET set_sftptrafficpolicy(cmd_rec *cmd) {
1608   CHECK_ARGS(cmd, 1);
1609   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1610 
1611   if (sftp_tap_have_policy(cmd->argv[1]) < 0) {
1612     CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", cmd->argv[1],
1613       "' is not a recognized policy", NULL));
1614   }
1615 
1616   (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
1617   return PR_HANDLED(cmd);
1618 }
1619 
1620 /* Event handlers
1621  */
1622 
sftp_chroot_ev(const void * event_data,void * user_data)1623 static void sftp_chroot_ev(const void *event_data, void *user_data) {
1624   (void) pr_table_add_dup(session.notes, "mod_sftp.chroot-path", event_data, 0);
1625 }
1626 
1627 extern pid_t mpid;
1628 
sftp_exit_ev(const void * event_data,void * user_data)1629 static void sftp_exit_ev(const void *event_data, void *user_data) {
1630 
1631   /* Close any channels/sessions that remain open. */
1632   sftp_channel_free();
1633 
1634   sftp_keys_free();
1635   sftp_kex_free();
1636 
1637   sftp_crypto_free(0);
1638   sftp_utf8_free();
1639 
1640   if (sftp_logfd >= 0) {
1641     (void) close(sftp_logfd);
1642     sftp_logfd = -1;
1643   }
1644 }
1645 
sftp_ban_class_ev(const void * event_data,void * user_data)1646 static void sftp_ban_class_ev(const void *event_data, void *user_data) {
1647   const char *proto;
1648 
1649   proto = pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT);
1650 
1651   /* Only send an SSH2 DISCONNECT if we're dealing with an SSH2 client. */
1652   if (strncmp(proto, "SSH2", 5) == 0) {
1653     sftp_disconnect_send(SFTP_SSH2_DISCONNECT_BY_APPLICATION, "Banned",
1654       __FILE__, __LINE__, "");
1655   }
1656 }
1657 
sftp_ban_host_ev(const void * event_data,void * user_data)1658 static void sftp_ban_host_ev(const void *event_data, void *user_data) {
1659   const char *proto;
1660 
1661   proto = pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT);
1662 
1663   /* Only send an SSH2 DISCONNECT if we're dealing with an SSH2 client. */
1664   if (strncmp(proto, "SSH2", 5) == 0) {
1665     char *ban_msg = "Banned", *name;
1666 
1667     name = user_data;
1668     if (name != NULL) {
1669       ban_msg = pstrcat(sftp_pool, "Host ", name, " has been banned", NULL);
1670     }
1671 
1672     sftp_disconnect_send(SFTP_SSH2_DISCONNECT_BY_APPLICATION, ban_msg,
1673       __FILE__, __LINE__, "");
1674   }
1675 }
1676 
sftp_ban_user_ev(const void * event_data,void * user_data)1677 static void sftp_ban_user_ev(const void *event_data, void *user_data) {
1678   const char *proto;
1679 
1680   proto = pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT);
1681 
1682   /* Only send an SSH2 DISCONNECT if we're dealing with an SSH2 client. */
1683   if (strncmp(proto, "SSH2", 5) == 0) {
1684     char *ban_msg = "Banned", *name;
1685 
1686     name = user_data;
1687     if (name != NULL) {
1688       ban_msg = pstrcat(sftp_pool, "User ", name, " has been banned", NULL);
1689     }
1690 
1691     sftp_disconnect_send(SFTP_SSH2_DISCONNECT_BY_APPLICATION, ban_msg,
1692       __FILE__, __LINE__, "");
1693   }
1694 }
1695 
sftp_max_conns_ev(const void * event_data,void * user_data)1696 static void sftp_max_conns_ev(const void *event_data, void *user_data) {
1697   const char *proto;
1698 
1699   proto = pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT);
1700 
1701   /* Only send an SSH2 DISCONNECT if we're dealing with an SSH2 client. */
1702   if (strncmp(proto, "SSH2", 5) == 0) {
1703     sftp_disconnect_send(SFTP_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS,
1704       "Maximum connections for host/user reached", __FILE__, __LINE__, "");
1705   }
1706 }
1707 
1708 #if defined(PR_SHARED_MODULE)
sftp_mod_unload_ev(const void * event_data,void * user_data)1709 static void sftp_mod_unload_ev(const void *event_data, void *user_data) {
1710   if (strncmp((const char *) event_data, "mod_sftp.c", 11) == 0) {
1711     /* Unregister ourselves from all events. */
1712     pr_event_unregister(&sftp_module, NULL, NULL);
1713 
1714     sftp_interop_free();
1715     sftp_keystore_free();
1716     sftp_keys_free();
1717     sftp_cipher_free();
1718     sftp_mac_free();
1719     pr_response_block(FALSE);
1720     sftp_utf8_free();
1721 
1722     /* Clean up the OpenSSL stuff. */
1723     sftp_crypto_free(0);
1724 
1725     destroy_pool(sftp_pool);
1726     sftp_pool = NULL;
1727 
1728     close(sftp_logfd);
1729     sftp_logfd = -1;
1730   }
1731 }
1732 #endif
1733 
sftp_postparse_ev(const void * event_data,void * user_data)1734 static void sftp_postparse_ev(const void *event_data, void *user_data) {
1735   config_rec *c;
1736   server_rec *s;
1737 
1738   /* Initialize OpenSSL. */
1739 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1740   OPENSSL_config(NULL);
1741 #endif /* prior to OpenSSL-1.1.x */
1742   ERR_load_crypto_strings();
1743   OpenSSL_add_all_algorithms();
1744 
1745   c = find_config(main_server->conf, CONF_PARAM, "SFTPPassPhraseProvider",
1746     FALSE);
1747   if (c) {
1748     sftp_keys_set_passphrase_provider(c->argv[0]);
1749   }
1750 
1751   sftp_keys_get_passphrases();
1752 
1753   /* Initialize the interoperability checks here, so that all session
1754    * processes share the compiled regexes in memory.
1755    */
1756   if (sftp_interop_init() < 0) {
1757     pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION
1758       ": error preparing interoperability checks: %s", strerror(errno));
1759   }
1760 
1761   /* Check for incompatible SFTPAuthMethods configurations.  For example,
1762    * configuring:
1763    *
1764    *  SFTPAuthMethods hostbased+password
1765    *
1766    * without also configuring SFTPAuthorizedHostKeys means that authentication
1767    * will never succeed.
1768    *
1769    * While here, we also check for unsupported configuration directives, and
1770    * warn if found.
1771    */
1772   for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
1773     int supports_hostbased = FALSE, supports_publickey = FALSE, use_sftp = FALSE;
1774 
1775     c = find_config(s->conf, CONF_PARAM, "SFTPEngine", FALSE);
1776     if (c != NULL) {
1777       use_sftp = *((int *) c->argv[0]);
1778     }
1779 
1780     if (use_sftp == FALSE) {
1781       /* No need to check further if mod_sftp is not enabled. */
1782       continue;
1783     }
1784 
1785     c = find_config(s->conf, CONF_PARAM, "SFTPAuthorizedHostKeys", FALSE);
1786     if (c != NULL) {
1787       supports_hostbased = TRUE;
1788     }
1789 
1790     c = find_config(s->conf, CONF_PARAM, "SFTPAuthorizedUserKeys", FALSE);
1791     if (c != NULL) {
1792       supports_publickey = TRUE;
1793     }
1794 
1795     c = find_config(s->conf, CONF_PARAM, "SFTPAuthMethods", FALSE);
1796     if (c != NULL) {
1797       register unsigned int i;
1798       array_header *auth_chains;
1799 
1800       auth_chains = c->argv[0];
1801 
1802       for (i = 0; i < auth_chains->nelts; i++) {
1803         register unsigned int j;
1804         struct sftp_auth_chain *auth_chain;
1805 
1806         auth_chain = ((struct sftp_auth_chain **) auth_chains->elts)[i];
1807         for (j = 0; j < auth_chain->methods->nelts; j++) {
1808           struct sftp_auth_method *meth;
1809 
1810           meth = ((struct sftp_auth_method **) auth_chain->methods->elts)[j];
1811 
1812           if (meth->method_id == SFTP_AUTH_FL_METH_HOSTBASED &&
1813               supports_hostbased == FALSE) {
1814             pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION
1815               ": Server '%s': cannot support authentication method '%s' "
1816               "without SFTPAuthorizedHostKeys configuration", s->ServerName,
1817               meth->method_name);
1818             pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BAD_CONFIG,
1819               NULL);
1820           }
1821 
1822           if (meth->method_id == SFTP_AUTH_FL_METH_PUBLICKEY &&
1823               supports_publickey == FALSE) {
1824             pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION
1825               ": Server '%s': cannot support authentication method '%s' "
1826               "without SFTPAuthorizedUserKeys configuration", s->ServerName,
1827               meth->method_name);
1828             pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BAD_CONFIG,
1829               NULL);
1830           }
1831         }
1832       }
1833     }
1834 
1835     /* The following directives are documented as not supported:
1836      *   <Anonymous>
1837      *   ListOptions
1838      *   MaxRetrieveFileSize
1839      */
1840 
1841     c = find_config(s->conf, CONF_ANON, NULL, FALSE);
1842     if (c != NULL) {
1843       pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION
1844         ": Server '%s': <Anonymous> configuration is not supported by "
1845         "mod_sftp, and will be ignored", s->ServerName);
1846     }
1847 
1848     c = find_config(s->conf, CONF_PARAM, "ListOptions", TRUE);
1849     if (c != NULL) {
1850       pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION
1851         ": Server '%s': ListOptions directive is not supported by mod_sftp, "
1852         "and will be ignored", s->ServerName);
1853     }
1854 
1855     c = find_config(s->conf, CONF_PARAM, "MaxRetrieveFileSize", TRUE);
1856     if (c != NULL) {
1857       pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION
1858         ": Server '%s': MaxRetrieveFileSize directive is not supported by "
1859         "mod_sftp, and will be ignored", s->ServerName);
1860     }
1861   }
1862 }
1863 
sftp_restart_ev(const void * event_data,void * user_data)1864 static void sftp_restart_ev(const void *event_data, void *user_data) {
1865 
1866   /* Clear the host keys. */
1867   sftp_keys_free();
1868 
1869   /* Clear the client banner regexes. */
1870   sftp_interop_free();
1871 }
1872 
sftp_shutdown_ev(const void * event_data,void * user_data)1873 static void sftp_shutdown_ev(const void *event_data, void *user_data) {
1874   sftp_interop_free();
1875   sftp_keystore_free();
1876   sftp_keys_free();
1877   sftp_cipher_free();
1878   sftp_mac_free();
1879   sftp_utf8_free();
1880 
1881   /* Clean up the OpenSSL stuff. */
1882   sftp_crypto_free(0);
1883 
1884   destroy_pool(sftp_pool);
1885   sftp_pool = NULL;
1886 
1887   if (sftp_logfd >= 0) {
1888     close(sftp_logfd);
1889     sftp_logfd = -1;
1890   }
1891 }
1892 
sftp_timeoutlogin_ev(const void * event_data,void * user_data)1893 static void sftp_timeoutlogin_ev(const void *event_data, void *user_data) {
1894   if (sftp_sess_state & SFTP_SESS_STATE_HAVE_KEX) {
1895     SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
1896   }
1897 }
1898 
1899 #ifdef PR_USE_DEVEL
pool_printf(const char * fmt,...)1900 static void pool_printf(const char *fmt, ...) {
1901   char buf[PR_TUNABLE_BUFFER_SIZE];
1902   va_list msg;
1903 
1904   memset(buf, '\0', sizeof(buf));
1905 
1906   va_start(msg, fmt);
1907   pr_vsnprintf(buf, sizeof(buf), fmt, msg);
1908   va_end(msg);
1909 
1910   buf[sizeof(buf)-1] = '\0';
1911   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s", buf);
1912 }
1913 
sftp_sigusr2_ev(const void * event_data,void * user_data)1914 static void sftp_sigusr2_ev(const void *event_data, void *user_data) {
1915   /* Note: the mod_shaper module deliberately uses the SIGUSR2 signal
1916    * for handling shaping.  Thus we only want to dump out the pools
1917    * IFF mod_shaper is NOT present.
1918    */
1919   if (pr_module_exists("mod_shaper.c") == FALSE) {
1920     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s",
1921       "-----BEGIN POOL DUMP-----");
1922     pr_pool_debug_memory(pool_printf);
1923     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s",
1924       "-----END POOL DUMP-----");
1925   }
1926 }
1927 #endif /* PR_USE_DEVEL */
1928 
sftp_wrap_conn_denied_ev(const void * event_data,void * user_data)1929 static void sftp_wrap_conn_denied_ev(const void *event_data, void *user_data) {
1930   const char *proto;
1931 
1932   proto = pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT);
1933 
1934   /* Only send an SSH2 DISCONNECT if we're dealing with an SSH2 client. */
1935   if (strncmp(proto, "SSH2", 5) == 0) {
1936     const char *msg;
1937 
1938     msg = get_param_ptr(main_server->conf, "WrapDenyMsg", FALSE);
1939     if (msg != NULL) {
1940       const char *user;
1941 
1942       user = session.user;
1943       if (user == NULL) {
1944         user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
1945       }
1946 
1947       /* If the client has authenticated, we can interpolate any '%u'
1948        * variable in the configured deny message.
1949        */
1950       msg = sreplace(sftp_pool, msg, "%u", user, NULL);
1951 
1952     } else {
1953       /* XXX This needs to be properly localized.  However, trying to use
1954        * the _("") construction here causes mod_sftp.c to fail compilation
1955        * (see Bug#3677), so leave it hardcoded for now.
1956        */
1957       msg = "Access denied";
1958     }
1959 
1960     /* If the client has completed the KEXINIT, we can simply use
1961      * sftp_disconnect_send().
1962      */
1963     if (sftp_sess_state & SFTP_SESS_STATE_HAVE_KEX) {
1964       sftp_disconnect_send(SFTP_SSH2_DISCONNECT_BY_APPLICATION, msg,
1965         __FILE__, __LINE__, "");
1966 
1967     } else {
1968       /* If the client has not completed the KEXINIT, then just send the
1969        * disconnected message, if any, directly.  Make sure to terminate
1970        * the message with a newline character.
1971        */
1972       msg = pstrcat(sftp_pool, msg, "\n", NULL);
1973 
1974       /* Make sure we block the Response API, otherwise mod_wrap/mod_wrap2 will
1975        * also be sending its response, and the SSH client may be confused.
1976        */
1977       pr_response_block(TRUE);
1978 
1979       if (write(session.c->wfd, msg, strlen(msg)) < 0) {
1980         pr_trace_msg("ssh2", 9,
1981           "error sending mod_wrap2 connection denied message to client: %s",
1982           strerror(errno));
1983       }
1984     }
1985   }
1986 }
1987 
1988 /* Initialization routines
1989  */
1990 
sftp_init(void)1991 static int sftp_init(void) {
1992   unsigned long openssl_version;
1993 
1994   /* Check that the OpenSSL headers used match the version of the
1995    * OpenSSL library used.
1996    *
1997    * For now, we only log if there is a difference.
1998    */
1999   openssl_version = SSLeay();
2000 
2001   if (openssl_version != OPENSSL_VERSION_NUMBER) {
2002     int unexpected_version_mismatch = TRUE;
2003 
2004     if (OPENSSL_VERSION_NUMBER >= 0x1000000fL) {
2005       /* OpenSSL versions after 1.0.0 try to maintain ABI compatibility.
2006        * So we will warn about header/library version mismatches only if
2007        * the library is older than the headers.
2008        */
2009       if (openssl_version >= OPENSSL_VERSION_NUMBER) {
2010         unexpected_version_mismatch = FALSE;
2011       }
2012     }
2013 
2014     if (unexpected_version_mismatch == TRUE) {
2015       pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION
2016         ": compiled using OpenSSL version '%s' headers, but linked to "
2017         "OpenSSL version '%s' library", OPENSSL_VERSION_TEXT,
2018         SSLeay_version(SSLEAY_VERSION));
2019     }
2020   }
2021 
2022   pr_log_debug(DEBUG2, MOD_SFTP_VERSION ": using " OPENSSL_VERSION_TEXT);
2023 
2024 #if defined(HAVE_SODIUM_H)
2025   if (sodium_init() < 0) {
2026     pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION
2027       ": error initializing libsodium");
2028 
2029   } else {
2030     const char *sodium_version;
2031 
2032     sodium_version = sodium_version_string();
2033     pr_log_debug(DEBUG2, MOD_SFTP_VERSION ": using libsodium-%s",
2034       sodium_version);
2035   }
2036 #endif /* HAVE_SODIUM_H */
2037 
2038   sftp_keystore_init();
2039   sftp_cipher_init();
2040   sftp_mac_init();
2041 
2042   pr_event_register(&sftp_module, "mod_ban.ban-class", sftp_ban_class_ev, NULL);
2043   pr_event_register(&sftp_module, "mod_ban.ban-host", sftp_ban_host_ev, NULL);
2044   pr_event_register(&sftp_module, "mod_ban.ban-user", sftp_ban_user_ev, NULL);
2045 
2046   /* Listen for mod_wrap/mod_wrap2 connection denied events, so that we can
2047    * attempt to display any deny messages from those modules to the connecting
2048    * SSH2 client.
2049    */
2050   pr_event_register(&sftp_module, "mod_wrap.connection-denied",
2051     sftp_wrap_conn_denied_ev, NULL);
2052 
2053 #if defined(PR_SHARED_MODULE)
2054   pr_event_register(&sftp_module, "core.module-unload", sftp_mod_unload_ev,
2055     NULL);
2056 #endif
2057   pr_event_register(&sftp_module, "core.postparse", sftp_postparse_ev, NULL);
2058   pr_event_register(&sftp_module, "core.restart", sftp_restart_ev, NULL);
2059   pr_event_register(&sftp_module, "core.shutdown", sftp_shutdown_ev, NULL);
2060   pr_event_register(&sftp_module, "core.timeout-login", sftp_timeoutlogin_ev,
2061     NULL);
2062 
2063   return 0;
2064 }
2065 
sftp_sess_init(void)2066 static int sftp_sess_init(void) {
2067   config_rec *c;
2068   int times_gmt = TRUE;
2069 
2070   c = find_config(main_server->conf, CONF_PARAM, "SFTPEngine", FALSE);
2071   if (c != NULL) {
2072     sftp_engine = *((int *) c->argv[0]);
2073   }
2074 
2075   if (sftp_engine == FALSE) {
2076     return 0;
2077   }
2078 
2079   pr_event_register(&sftp_module, "core.chroot", sftp_chroot_ev, NULL);
2080   pr_event_register(&sftp_module, "core.exit", sftp_exit_ev, NULL);
2081 #ifdef PR_USE_DEVEL
2082   pr_event_register(&sftp_module, "core.signal.USR2", sftp_sigusr2_ev, NULL);
2083 #endif /* PR_USE_DEVEL */
2084   pr_event_register(&sftp_module, "mod_auth.max-clients",
2085     sftp_max_conns_ev, NULL);
2086   pr_event_register(&sftp_module, "mod_auth.max-clients-per-class",
2087     sftp_max_conns_ev, NULL);
2088   pr_event_register(&sftp_module, "mod_auth.max-clients-per-host",
2089     sftp_max_conns_ev, NULL);
2090   pr_event_register(&sftp_module, "mod_auth.max-clients-per-user",
2091     sftp_max_conns_ev, NULL);
2092   pr_event_register(&sftp_module, "mod_auth.max-connections-per-host",
2093     sftp_max_conns_ev, NULL);
2094   pr_event_register(&sftp_module, "mod_auth.max-hosts-per-user",
2095     sftp_max_conns_ev, NULL);
2096 
2097   c = find_config(main_server->conf, CONF_PARAM, "SFTPLog", FALSE);
2098   if (c != NULL) {
2099     sftp_logname = c->argv[0];
2100 
2101     if (strcasecmp(sftp_logname, "none") != 0) {
2102       int res, xerrno;
2103 
2104       pr_signals_block();
2105       PRIVS_ROOT
2106       res = pr_log_openfile(sftp_logname, &sftp_logfd, PR_LOG_SYSTEM_MODE);
2107       xerrno = errno;
2108       PRIVS_RELINQUISH
2109       pr_signals_unblock();
2110 
2111       if (res < 0) {
2112         if (res == -1) {
2113           pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION
2114             ": notice: unable to open SFTPLog '%s': %s", sftp_logname,
2115             strerror(xerrno));
2116 
2117         } else if (res == PR_LOG_WRITABLE_DIR) {
2118           pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION
2119             ": notice: unable to open SFTPLog '%s': parent directory is "
2120             "world-writable", sftp_logname);
2121 
2122         } else if (res == PR_LOG_SYMLINK) {
2123           pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION
2124             ": notice: unable to open SFTPLog '%s': cannot log to a symlink",
2125             sftp_logname);
2126         }
2127       }
2128     }
2129   }
2130 
2131   if (pr_define_exists("SFTP_USE_FIPS")) {
2132 #ifdef OPENSSL_FIPS
2133     if (!FIPS_mode()) {
2134 
2135       /* Make sure OpenSSL is set to use the default RNG, as per an email
2136        * discussion on the OpenSSL developer list:
2137        *
2138        *  "The internal FIPS logic uses the default RNG to see the FIPS RNG
2139        *   as part of the self test process..."
2140        */
2141       RAND_set_rand_method(NULL);
2142 
2143       if (!FIPS_mode_set(1)) {
2144         const char *errstr;
2145 
2146         errstr = sftp_crypto_get_errors();
2147         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2148           "unable to use FIPS mode: %s", errstr);
2149         pr_log_pri(PR_LOG_ERR, MOD_SFTP_VERSION ": unable to use FIPS mode: %s",
2150           errstr);
2151 
2152         errno = EACCES;
2153         return -1;
2154 
2155       } else {
2156         pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_VERSION ": FIPS mode enabled");
2157       }
2158 
2159     } else {
2160       pr_log_pri(PR_LOG_DEBUG, MOD_SFTP_VERSION ": FIPS mode already enabled");
2161     }
2162 #else
2163     pr_log_pri(PR_LOG_WARNING, MOD_SFTP_VERSION ": FIPS mode requested, but " OPENSSL_VERSION_TEXT " not built with FIPS support");
2164 #endif /* OPENSSL_FIPS */
2165   }
2166 
2167 #if OPENSSL_VERSION_NUMBER > 0x000907000L
2168   /* Handle any requested crypto accelerators/drivers. */
2169   c = find_config(main_server->conf, CONF_PARAM, "SFTPCryptoDevice", FALSE);
2170   if (c) {
2171     if (sftp_crypto_set_driver(c->argv[0]) < 0) {
2172       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2173         "unable use SFTPCryptoDevice '%s': %s", (const char *) c->argv[0],
2174         strerror(errno));
2175     }
2176   }
2177 #endif
2178 
2179   sftp_pool = make_sub_pool(session.pool);
2180   pr_pool_tag(sftp_pool, MOD_SFTP_VERSION);
2181 
2182   /* Clear out FTP-isms. */
2183   session.data_port = 0;
2184 
2185   c = find_config(main_server->conf, CONF_PARAM, "SFTPOptions", FALSE);
2186   while (c != NULL) {
2187     unsigned long opts;
2188 
2189     pr_signals_handle();
2190 
2191     opts = *((unsigned long *) c->argv[0]);
2192     sftp_opts |= opts;
2193 
2194     c = find_config_next(c, c->next, CONF_PARAM, "SFTPOptions", FALSE);
2195   }
2196 
2197   /* We do two passes through the configured hostkeys.  On the first pass,
2198    * we focus on loading all of the configured keys.  On the second pass,
2199    * we focus on handling any of the hostkey flags that would e.g. clear the
2200    * previously loaded keys.
2201    */
2202 
2203   c = find_config(main_server->conf, CONF_PARAM, "SFTPHostKey", FALSE);
2204   while (c) {
2205     const char *path = c->argv[0];
2206     int flags = *((int *) c->argv[1]);
2207 
2208     if (path != NULL &&
2209         flags == 0) {
2210       /* This pool needs to have the lifetime of the session, since the hostkey
2211        * data is needed for rekeying, and rekeying can happen at any time
2212        * during the session.
2213        */
2214       if (sftp_keys_get_hostkey(sftp_pool, path) < 0) {
2215         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2216           "error loading hostkey '%s', skipping key", path);
2217       }
2218     }
2219 
2220     c = find_config_next(c, c->next, CONF_PARAM, "SFTPHostKey", FALSE);
2221   }
2222 
2223   c = find_config(main_server->conf, CONF_PARAM, "SFTPHostKey", FALSE);
2224   while (c) {
2225     int flags = *((int *) c->argv[1]);
2226 
2227     if (flags != 0) {
2228       /* Handle any flags, such as for clearing previous host keys. */
2229       if (flags & SFTP_HOSTKEY_FL_CLEAR_RSA_KEY) {
2230         if (sftp_keys_clear_rsa_hostkey() < 0) {
2231           pr_trace_msg(trace_channel, 13,
2232             "error clearing RSA hostkey: %s", strerror(errno));
2233 
2234         } else {
2235           pr_trace_msg(trace_channel, 9, "cleared RSA hostkey");
2236         }
2237 
2238       } else if (flags & SFTP_HOSTKEY_FL_CLEAR_DSA_KEY) {
2239         if (sftp_keys_clear_dsa_hostkey() < 0) {
2240           pr_trace_msg(trace_channel, 13,
2241             "error clearing DSA hostkey: %s", strerror(errno));
2242 
2243         } else {
2244           pr_trace_msg(trace_channel, 9, "cleared DSA hostkey");
2245         }
2246 
2247       } else if (flags & SFTP_HOSTKEY_FL_CLEAR_ECDSA_KEY) {
2248         if (sftp_keys_clear_ecdsa_hostkey() < 0) {
2249           pr_trace_msg(trace_channel, 13,
2250             "error clearing ECDSA hostkey(s): %s", strerror(errno));
2251 
2252         } else {
2253           pr_trace_msg(trace_channel, 9, "cleared ECDSA hostkey(s)");
2254         }
2255 
2256       } else if (flags & SFTP_HOSTKEY_FL_CLEAR_ED25519_KEY) {
2257         if (sftp_keys_clear_ed25519_hostkey() < 0) {
2258           pr_trace_msg(trace_channel, 13,
2259             "error clearing ED25519 hostkey(s): %s", strerror(errno));
2260 
2261         } else {
2262           pr_trace_msg(trace_channel, 9, "cleared ED25519 hostkey(s)");
2263         }
2264       }
2265     }
2266 
2267     c = find_config_next(c, c->next, CONF_PARAM, "SFTPHostKey", FALSE);
2268   }
2269 
2270   /* Support having either an RSA hostkey, a DSA hostkey, an ECDSA hostkey,
2271    * an ED25519 hostkey, or any combination thereof.  But we have to have at
2272    * least one hostkey.
2273    */
2274   if (sftp_keys_have_dsa_hostkey() < 0 &&
2275       sftp_keys_have_rsa_hostkey() < 0 &&
2276       sftp_keys_have_ecdsa_hostkey(sftp_pool, NULL) < 0 &&
2277       sftp_keys_have_ed25519_hostkey()) {
2278     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2279       "no available host keys, unable to handle session");
2280     errno = EACCES;
2281     return -1;
2282   }
2283 
2284   c = find_config(main_server->conf, CONF_PARAM, "SFTPKeyLimits", FALSE);
2285   if (c != NULL) {
2286     int rsa_min = -1, dsa_min = -1, ec_min = -1;
2287 
2288     if (c->argv[0] != NULL) {
2289       rsa_min = *((int *) c->argv[0]);
2290     }
2291 
2292     if (c->argv[1] != NULL) {
2293       dsa_min = *((int *) c->argv[1]);
2294     }
2295 
2296     if (c->argv[2] != NULL) {
2297       ec_min = *((int *) c->argv[2]);
2298     }
2299 
2300     if (rsa_min > -1 ||
2301         dsa_min > -1 ||
2302         ec_min > -1) {
2303       if (sftp_keys_set_key_limits(rsa_min, dsa_min, ec_min) < 0) {
2304         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2305           "error setting SFTPKeyLimits: %s", strerror(errno));
2306       }
2307     }
2308   }
2309 
2310   c = find_config(main_server->conf, CONF_PARAM, "SFTPKeyBlacklist", FALSE);
2311   if (c != NULL) {
2312     if (strncasecmp((char *) c->argv[0], "none", 5) != 0) {
2313       sftp_blacklist_set_file(c->argv[0]);
2314 
2315     } else {
2316       /* Admin explicitly requested no checking of a key blacklist. */
2317       sftp_blacklist_set_file(NULL);
2318     }
2319   }
2320 
2321   c = find_config(main_server->conf, CONF_PARAM, "SFTPMaxChannels", FALSE);
2322   if (c) {
2323     sftp_channel_set_max_count(*((unsigned int *) c->argv[0]));
2324   }
2325 
2326   c = find_config(main_server->conf, CONF_PARAM, "DisplayLogin", FALSE);
2327   if (c) {
2328     const char *path;
2329 
2330     path = c->argv[0];
2331     if (sftp_fxp_set_displaylogin(path) < 0) {
2332       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2333         "error using DisplayLogin '%s': %s", path, strerror(errno));
2334     }
2335   }
2336 
2337   c = find_config(main_server->conf, CONF_PARAM, "ServerIdent", FALSE);
2338   if (c) {
2339     if (*((unsigned char *) c->argv[0]) == FALSE) {
2340       /* The admin configured "ServerIdent off".  Set the version string to
2341        * just "mod_sftp", and that's it, no version.
2342        */
2343       sftp_server_version = pstrcat(sftp_pool, SFTP_ID_PREFIX, "mod_sftp",
2344         NULL);
2345       sftp_ssh2_packet_set_version(sftp_server_version);
2346 
2347     } else {
2348       /* The admin configured "ServerIdent on", and possibly some custom
2349        * string.
2350        */
2351       if (c->argc > 1) {
2352         sftp_server_version = pstrcat(sftp_pool, SFTP_ID_PREFIX, c->argv[1],
2353           NULL);
2354         sftp_ssh2_packet_set_version(sftp_server_version);
2355       }
2356     }
2357   }
2358 
2359   c = find_config(main_server->conf, CONF_PARAM, "TimesGMT", FALSE);
2360   if (c) {
2361     times_gmt = *((unsigned char *) c->argv[0]);
2362   }
2363 
2364   pr_response_block(TRUE);
2365 
2366   c = find_config(main_server->conf, CONF_PARAM, "SFTPExtensions", FALSE);
2367   if (c) {
2368     sftp_fxp_set_extensions(*((unsigned long *) c->argv[0]));
2369   }
2370 
2371   sftp_fxp_use_gmt(times_gmt);
2372 
2373   c = find_config(main_server->conf, CONF_PARAM, "SFTPClientAlive", FALSE);
2374   if (c) {
2375     unsigned int count, interval;
2376 
2377     count = *((unsigned int *) c->argv[0]);
2378     interval = *((unsigned int *) c->argv[1]);
2379 
2380     (void) sftp_ssh2_packet_set_client_alive(count, interval);
2381 
2382     pr_trace_msg("ssh2", 7,
2383       "client alive checks requested after %u secs, up to %u times",
2384       interval, count);
2385   }
2386 
2387   /* Check for any rekey policy. */
2388   c = find_config(main_server->conf, CONF_PARAM, "SFTPRekey", FALSE);
2389   if (c) {
2390     int rekey;
2391 
2392     /* The possible int values here are:
2393      *
2394      * 0 (disable rekeying)
2395      * 1 (enable rekeying, with parameters)
2396      */
2397 
2398     rekey = *((int *) c->argv[0]);
2399     if (rekey) {
2400       int rekey_interval;
2401       off_t rekey_size;
2402 
2403       rekey_interval = *((int *) c->argv[1]);
2404       rekey_size = *((off_t *) c->argv[2]);
2405 
2406       pr_trace_msg("ssh2", 6, "SSH2 rekeys requested after %d secs "
2407         "or %" PR_LU " bytes", rekey_interval, (pr_off_t) rekey_size);
2408       sftp_kex_rekey_set_interval(rekey_interval);
2409       sftp_ssh2_packet_rekey_set_size(rekey_size);
2410 
2411       if (c->argc == 4) {
2412         int rekey_timeout;
2413 
2414         rekey_timeout = *((int *) c->argv[3]);
2415 
2416         pr_trace_msg("ssh2", 6, "SSH2 rekeying has %d %s to complete",
2417           rekey_timeout, rekey_timeout != 1 ? "secs" : "sec");
2418         sftp_kex_rekey_set_timeout(rekey_timeout);
2419       }
2420 
2421     } else {
2422       sftp_kex_rekey_set_interval(0);
2423       sftp_kex_rekey_set_timeout(0);
2424       sftp_ssh2_packet_rekey_set_seqno(0);
2425       sftp_ssh2_packet_rekey_set_size(0);
2426 
2427       pr_trace_msg("ssh2", 6,
2428         "SSH2 server-requested rekeys disabled by SFTPRekey");
2429     }
2430 
2431   } else {
2432 
2433     /* Set the default rekey values: 1 hour (3600 secs) and 2 GB.
2434      * Also, as per RFC4344, rekeys will be requested whenever the
2435      * packet sequence numbers reach rollover; these are handled by
2436      * default in packet.c.
2437      */
2438     sftp_kex_rekey_set_interval(3600);
2439     sftp_ssh2_packet_rekey_set_size((off_t) 2147483648UL);
2440   }
2441 
2442   /* Enable traffic analysis protection (TAP) after keys have been
2443    * exchanged, based on the configured policy.
2444    */
2445   c = find_config(main_server->conf, CONF_PARAM, "SFTPTrafficPolicy", FALSE);
2446   if (c) {
2447     const char *policy = c->argv[0];
2448 
2449     if (sftp_tap_set_policy(policy) < 0) {
2450       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2451         "error setting TrafficPolicy '%s': %s", policy, strerror(errno));
2452 
2453     } else {
2454       pr_trace_msg("ssh2", 9, "using TAP policy '%s'", policy);
2455     }
2456   }
2457 
2458   pr_session_set_protocol("ssh2");
2459 
2460   /* Use our own "authenticated yet?" check. */
2461   set_auth_check(sftp_have_authenticated);
2462 
2463   pr_cmd_set_handler(sftp_cmd_loop);
2464 
2465   /* Check for any UseEncoding directives.  Specifically, we're interested
2466    * in the charset portion; the encoding is always UTF8 for SFTP clients
2467    * (when applicable).
2468    */
2469 
2470   c = find_config(main_server->conf, CONF_PARAM, "UseEncoding", FALSE);
2471   if (c) {
2472     if (c->argc == 2) {
2473       char *charset;
2474 
2475       charset = c->argv[0];
2476 
2477       if (sftp_utf8_set_charset(charset) < 0) {
2478         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2479           "error setting local charset '%s': %s", charset, strerror(errno));
2480 
2481         /* Re-initialize the UTF8 conversion handles. */
2482         (void) sftp_utf8_free();
2483         sftp_utf8_init();
2484       }
2485 
2486     } else {
2487       sftp_utf8_init();
2488     }
2489 
2490   } else {
2491     sftp_utf8_init();
2492   }
2493 
2494   return 0;
2495 }
2496 
2497 /* Module API tables
2498  */
2499 
2500 static conftable sftp_conftab[] = {
2501   { "SFTPAcceptEnv",		set_sftpacceptenv,		NULL },
2502   { "SFTPAuthMethods",		set_sftpauthmeths,		NULL },
2503   { "SFTPAuthorizedHostKeys",	set_sftpauthorizedkeys,		NULL },
2504   { "SFTPAuthorizedUserKeys",	set_sftpauthorizedkeys,		NULL },
2505   { "SFTPCiphers",		set_sftpciphers,		NULL },
2506   { "SFTPClientAlive",		set_sftpclientalive,		NULL },
2507   { "SFTPClientMatch",		set_sftpclientmatch,		NULL },
2508   { "SFTPCompression",		set_sftpcompression,		NULL },
2509   { "SFTPCryptoDevice",		set_sftpcryptodevice,		NULL },
2510   { "SFTPDHParamFile",		set_sftpdhparamfile,		NULL },
2511   { "SFTPDigests",		set_sftpdigests,		NULL },
2512   { "SFTPDisplayBanner",	set_sftpdisplaybanner,		NULL },
2513   { "SFTPEngine",		set_sftpengine,			NULL },
2514   { "SFTPExtensions",		set_sftpextensions,		NULL },
2515   { "SFTPHostKey",		set_sftphostkey,		NULL },
2516   { "SFTPKeyBlacklist",		set_sftpkeyblacklist,		NULL },
2517   { "SFTPKeyExchanges",		set_sftpkeyexchanges,		NULL },
2518   { "SFTPKeyLimits",		set_sftpkeylimits,		NULL },
2519   { "SFTPLog",			set_sftplog,			NULL },
2520   { "SFTPMaxChannels",		set_sftpmaxchannels,		NULL },
2521   { "SFTPOptions",		set_sftpoptions,		NULL },
2522   { "SFTPPassPhraseProvider",	set_sftppassphraseprovider,	NULL },
2523   { "SFTPRekey",		set_sftprekey,			NULL },
2524   { "SFTPTrafficPolicy",	set_sftptrafficpolicy,		NULL },
2525   { NULL }
2526 };
2527 
2528 module sftp_module = {
2529   /* Always NULL */
2530   NULL, NULL,
2531 
2532   /* Module API version */
2533   0x20,
2534 
2535   /* Module name */
2536   "sftp",
2537 
2538   /* Module configuration handler table */
2539   sftp_conftab,
2540 
2541   /* Module command handler table */
2542   NULL,
2543 
2544   /* Module authentication handler table */
2545   NULL,
2546 
2547   /* Module initialization */
2548   sftp_init,
2549 
2550   /* Session initialization */
2551   sftp_sess_init,
2552 
2553   /* Module version */
2554   MOD_SFTP_VERSION
2555 };
2556 
2557