1 /*
2  * ProFTPD - mod_sftp traffic analysis protection
3  * Copyright (c) 2008-2016 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 "tap.h"
30 #include "interop.h"
31 
32 extern module sftp_module;
33 
34 static pool *tap_pool = NULL;
35 static int tap_timerno = -1;
36 
37 static const char *trace_channel = "ssh2";
38 
39 struct sftp_tap_policy {
40   const char *policy;
41 
42   unsigned int chance_max;
43   unsigned int chance;
44   unsigned int min_datalen;
45   unsigned int max_datalen;
46 
47   int check_interval;
48   unsigned long min_secs;
49   unsigned long max_secs;
50 };
51 
52 static struct sftp_tap_policy tap_policies[] = {
53   { "none",	0,	0,	0,	0,	0,	0,	0 },
54   { "low",	1000,	0,	64,	256,	5,	15,	300 },
55   { "medium",	100,	0,	32,	768,	5,	10,	60 },
56   { "high",	10,	0,	16,	2048,	1,	5,	15 },
57   { "paranoid",	1,	0,	0,	0,	1,	1,	5 },
58   { "rogaway", 	1,	0,	64,	256,	0,	0,	0 },
59   { NULL,	0,	0,	0,	0,	0,	0,	0 }
60 };
61 
62 static struct sftp_tap_policy curr_policy = { NULL, 0, 0, 0, 0, 0, 0, 0 };
63 
64 /* This only checks whether to TRY to send a TAP packet; it does not force
65  * a TAP packet to be sent.  The request to send a TAP packet, if we try,
66  * is still subject to the 1-in-N chance of sending a packet as set by
67  * the selected policy.
68  */
check_packet_times_cb(CALLBACK_FRAME)69 static int check_packet_times_cb(CALLBACK_FRAME) {
70   time_t last_recvd, last_sent, now;
71   unsigned long since_recvd, since_sent;
72   unsigned int chance;
73   int rnd;
74 
75   /* Always return 1 so that this timer is rescheduled. */
76 
77   sftp_ssh2_packet_get_last_recvd(&last_recvd);
78   sftp_ssh2_packet_get_last_sent(&last_sent);
79   time(&now);
80 
81   since_recvd = now - last_recvd;
82   since_sent = now - last_sent;
83 
84   /* If it's been less than min_secs, do NOT send a packet. */
85   if (since_recvd <= curr_policy.min_secs &&
86       since_sent <= curr_policy.max_secs) {
87     return 1;
88   }
89 
90   /* If it's been more than max_secs, DO attempt send a packet. */
91   if (since_recvd >= curr_policy.max_secs &&
92       since_sent >= curr_policy.max_secs) {
93     pr_trace_msg(trace_channel, 15, "too much inactivity, attempting "
94       "to send TAP packet");
95 
96     if (sftp_tap_send_packet() < 0) {
97       pr_trace_msg(trace_channel, 3, "error sending TAP packet: %s",
98         strerror(errno));
99     }
100 
101     return 1;
102   }
103 
104   /* Otherwise, pick a random number, see if it's time to send a packet. */
105   if (curr_policy.chance_max != 1) {
106     rnd = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1));
107 
108   } else {
109     rnd = 1;
110   }
111 
112   chance = rnd;
113   if (chance == curr_policy.chance) {
114     pr_trace_msg(trace_channel, 15, "perhaps too inactive, attempting to send "
115       "a TAP packet");
116 
117     if (sftp_tap_send_packet() < 0) {
118       pr_trace_msg(trace_channel, 3, "error sending TAP packet: %s",
119         strerror(errno));
120     }
121 
122     return 1;
123   }
124 
125   return 1;
126 }
127 
copy_policy(struct sftp_tap_policy * dst,struct sftp_tap_policy * src)128 static void copy_policy(struct sftp_tap_policy *dst,
129   struct sftp_tap_policy *src) {
130 
131   dst->policy = src->policy;
132   dst->chance_max = src->chance_max;
133   dst->min_datalen = src->min_datalen;
134   dst->max_datalen = src->max_datalen;
135 }
136 
set_policy_chance(struct sftp_tap_policy * policy)137 static void set_policy_chance(struct sftp_tap_policy *policy) {
138   if (policy->chance_max == 0) {
139     /* This is the 'none' policy; no need to do anything. */
140     return;
141   }
142 
143   if (policy->chance_max != 1) {
144     policy->chance = (int) (rand() / (RAND_MAX / policy->chance_max + 1));
145 
146   } else {
147     policy->chance = 1;
148   }
149 }
150 
set_policy_timer(struct sftp_tap_policy * policy)151 static void set_policy_timer(struct sftp_tap_policy *policy) {
152 
153   /* Start a timer which checks the last times we received and sent packets.
154    * From there, we may want to inject a TAP message, depending on the
155    * policy.
156    */
157   if (policy->check_interval > 0) {
158     tap_timerno = pr_timer_add(policy->check_interval, -1,
159       &sftp_module, check_packet_times_cb, "SFTP TAP check");
160   }
161 }
162 
sftp_tap_have_policy(const char * policy)163 int sftp_tap_have_policy(const char *policy) {
164   register unsigned int i;
165 
166   for (i = 0; tap_policies[i].policy; i++) {
167     if (strcasecmp(tap_policies[i].policy, policy) == 0) {
168       return 0;
169     }
170   }
171 
172   errno = ENOENT;
173   return -1;
174 }
175 
sftp_tap_send_packet(void)176 int sftp_tap_send_packet(void) {
177   int rnd;
178   unsigned int chance;
179 
180   if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) {
181     pr_trace_msg(trace_channel, 3,
182       "unable to send TAP packet: IGNORE not supported by client");
183     return 0;
184   }
185 
186   if (curr_policy.chance_max == 0) {
187     /* The "none" policy is in effect; nothing to do. */
188     return 0;
189   }
190 
191   /* Calculate our odds of sending a tap packet, based on the configured
192    * policy.
193    */
194   if (curr_policy.chance_max != 1) {
195     rnd = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1));
196 
197   } else {
198     rnd = 1;
199   }
200 
201   chance = rnd;
202   if (chance == curr_policy.chance) {
203     unsigned char *buf, *ptr, *rand_data;
204     uint32_t bufsz, buflen, rand_datalen;
205     struct ssh2_packet *pkt;
206     unsigned int max_datalen = 8192;
207 
208     if (curr_policy.max_datalen) {
209       max_datalen = curr_policy.max_datalen;
210     }
211 
212     rand_datalen = (uint32_t) (curr_policy.min_datalen + rand() /
213       (RAND_MAX / (max_datalen - curr_policy.min_datalen) + 1));
214 
215     pr_trace_msg(trace_channel, 20,  "sending random SSH2_MSG_IGNORE message "
216       "(%lu bytes) based on '%s' TAP policy", (unsigned long) rand_datalen,
217       curr_policy.policy);
218 
219     pkt = sftp_ssh2_packet_create(tap_pool);
220     bufsz = buflen = rand_datalen + 32;
221     ptr = buf = palloc(pkt->pool, bufsz);
222 
223     rand_data = palloc(pkt->pool, rand_datalen);
224 
225     RAND_bytes(rand_data, rand_datalen);
226 
227     sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_IGNORE);
228     sftp_msg_write_data(&buf, &buflen, rand_data, rand_datalen, TRUE);
229 
230     pkt->payload = ptr;
231     pkt->payload_len = (bufsz - buflen);
232 
233     if (sftp_ssh2_packet_send(sftp_conn->wfd, pkt) < 0) {
234       int xerrno = errno;
235 
236       pr_trace_msg(trace_channel, 12,
237         "error writing TAP packet: %s", strerror(xerrno));
238     }
239 
240     destroy_pool(pkt->pool);
241   }
242 
243   return 0;
244 }
245 
sftp_tap_set_policy(const char * policy)246 int sftp_tap_set_policy(const char *policy) {
247   register unsigned int i;
248 
249   if (tap_pool) {
250 
251     /* Special case: IFF the existing policy is 'none' AND the given
252      * policy is 'rogaway', just return.  The 'none' policy must have been
253      * explicitly configured, and it should override the automatic use of
254      * the 'rogaway' policy.
255      */
256     if (strncmp(curr_policy.policy, "none", 5) == 0 &&
257         strncasecmp(policy, "rogaway", 8) == 0) {
258       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
259         "'none' traffic policy explicitly configured, ignoring '%s' policy",
260         policy);
261       return 0;
262     }
263 
264     destroy_pool(tap_pool);
265 
266     if (tap_timerno > 0) {
267       pr_timer_remove(tap_timerno, &sftp_module);
268       tap_timerno = -1;
269     }
270   }
271 
272   tap_pool = make_sub_pool(sftp_pool);
273   pr_pool_tag(tap_pool, "SFTP TAP Pool");
274 
275   memset(&curr_policy, 0, sizeof(struct sftp_tap_policy));
276 
277   for (i = 0; tap_policies[i].policy; i++) {
278     if (strcasecmp(tap_policies[i].policy, policy) == 0) {
279       copy_policy(&curr_policy, &(tap_policies[i]));
280       set_policy_chance(&curr_policy);
281       set_policy_timer(&curr_policy);
282       return 0;
283     }
284   }
285 
286   errno = ENOENT;
287   return -1;
288 }
289