source: src/router/proftpd/contrib/mod_sftp/msg.c @ 17876

Last change on this file since 17876 was 17876, checked in by BrainSlayer, 19 months ago

update proftp

File size: 10.0 KB
Line 
1/*
2 * ProFTPD - mod_sftp message format
3 * Copyright (c) 2008-2011 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 * $Id: msg.c,v 1.7 2011/05/23 21:03:12 castaglia Exp $
25 */
26
27#include "mod_sftp.h"
28#include "ssh2.h"
29#include "msg.h"
30#include "crypto.h"
31#include "disconnect.h"
32
33#ifdef HAVE_EXECINFO_H
34# include <execinfo.h>
35#endif
36
37/* The scratch buffer used by getbuf() is a constant 8KB.  If the caller
38 * requests a larger size than that, the request is fulfilled using the
39 * caller-provided pool.
40 */
41static char msg_buf[8 * 1024];
42
43static void log_stacktrace(void) {
44#if defined(HAVE_EXECINFO_H) && \
45    defined(HAVE_BACKTRACE) && \
46    defined(HAVE_BACKTRACE_SYMBOLS)
47  void *trace[PR_TUNABLE_CALLER_DEPTH];
48  char **strings;
49  size_t tracesz;
50
51  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
52    "-----BEGIN STACK TRACE-----");
53
54  tracesz = backtrace(trace, PR_TUNABLE_CALLER_DEPTH);
55  strings = backtrace_symbols(trace, tracesz);
56  if (strings != NULL) {
57    register unsigned int i;
58
59    for (i = 1; i < tracesz; i++) {
60      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
61        "[%u] %s", i-1, strings[i]);
62    }
63
64    /* Prevent memory leaks. */
65    free(strings);
66
67  } else {
68    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
69      "error obtaining stacktrace symbols: %s", strerror(errno));
70  }
71 
72  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
73    "-----END STACK TRACE-----");
74#endif
75}
76
77char *sftp_msg_getbuf(pool *p, size_t sz) {
78  if (sz <= sizeof(msg_buf)) {
79    return msg_buf;
80  }
81
82  return palloc(p, sz);
83}
84
85char sftp_msg_read_byte(pool *p, char **buf, uint32_t *buflen) {
86  char byte = 0;
87
88  (void) p;
89
90  if (*buflen < sizeof(char)) {
91    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
92      "message format error: unable to read byte (buflen = %lu)",
93      (unsigned long) *buflen);
94    log_stacktrace();
95    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
96  }
97
98  memcpy(&byte, *buf, sizeof(char));
99  (*buf) += sizeof(char);
100  (*buflen) -= sizeof(char);
101
102  return byte;
103}
104
105int sftp_msg_read_bool(pool *p, char **buf, uint32_t *buflen) {
106  char bool = 0;
107
108  (void) p;
109
110  bool = sftp_msg_read_byte(p, buf, buflen);
111  if (bool == 0)
112    return 0;
113
114  return 1;
115}
116
117char *sftp_msg_read_data(pool *p, char **buf, uint32_t *buflen,
118    size_t datalen) {
119  char *data = NULL;
120
121  if (*buflen < datalen) {
122    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
123      "message format error: unable to read %lu bytes of raw data "
124      "(buflen = %lu)", (unsigned long) datalen, (unsigned long) *buflen);
125    log_stacktrace();
126    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
127  }
128
129  data = palloc(p, datalen);
130
131  memcpy(data, *buf, datalen);
132  (*buf) += datalen;
133  (*buflen) -= datalen;
134
135  return data;
136}
137
138uint32_t sftp_msg_read_int(pool *p, char **buf, uint32_t *buflen) {
139  uint32_t val = 0;
140
141  (void) p;
142
143  if (*buflen < sizeof(uint32_t)) {
144    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
145      "message format error: unable to read int (buflen = %lu)",
146      (unsigned long) *buflen);
147    log_stacktrace();
148    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
149  }
150
151  memcpy(&val, *buf, sizeof(uint32_t));
152  (*buf) += sizeof(uint32_t);
153  (*buflen) -= sizeof(uint32_t);
154
155  val = ntohl(val);
156  return val;
157}
158
159BIGNUM *sftp_msg_read_mpint(pool *p, char **buf, uint32_t *buflen) {
160  BIGNUM *mpint = NULL;
161  const unsigned char *data = NULL;
162  uint32_t datalen = 0;
163
164  datalen = sftp_msg_read_int(p, buf, buflen);
165
166  if (*buflen < datalen) {
167    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
168      "message format error: unable to read %lu bytes of mpint (buflen = %lu)",
169      (unsigned long) datalen, (unsigned long) *buflen);
170    log_stacktrace();
171    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
172  }
173
174  if (datalen > (1024 * 16)) {
175    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
176      "message format error: unable to handle mpint of %lu bytes",
177      (unsigned long) datalen);
178    log_stacktrace();
179    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
180  }
181
182  data = (const unsigned char *) sftp_msg_read_data(p, buf, buflen, datalen);
183  if (data == NULL) {
184    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
185      "message format error: unable to read %lu bytes of mpint data",
186      (unsigned long) datalen);
187    log_stacktrace();
188    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
189  }
190
191  if (data[0] & 0x80) {
192    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
193      "message format error: negative mpint numbers not supported");
194    log_stacktrace();
195    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
196  }
197
198  mpint = BN_bin2bn(data, (int) datalen, NULL);
199  if (mpint == NULL) {
200    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
201      "message format error: unable to convert binary mpint: %s",
202      sftp_crypto_get_errors());
203    log_stacktrace();
204    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
205  }
206
207  return mpint;
208}
209
210char *sftp_msg_read_string(pool *p, char **buf, uint32_t *buflen) {
211  uint32_t len = 0;
212  char *str = NULL;
213
214  len = sftp_msg_read_int(p, buf, buflen);
215
216  /* We can't use sftp_msg_read_data() here, since we need to allocate and
217   * populate a buffer that is one byte longer than the len just read in,
218   * for the terminating NUL.
219   */
220
221  if (*buflen < len) {
222    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
223      "message format error: unable to read %lu bytes of string data "
224      "(buflen = %lu)", (unsigned long) len, (unsigned long) *buflen);
225    log_stacktrace();
226    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
227  }
228
229  str = palloc(p, len + 1);
230
231  memcpy(str, *buf, len);
232  (*buf) += len;
233  (*buflen) -= len;
234  str[len] = '\0';
235
236  return str;
237}
238
239void sftp_msg_write_byte(char **buf, uint32_t *buflen, char byte) {
240  if (*buflen < sizeof(char)) {
241    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
242      "message format error: unable to write byte (buflen = %lu)",
243      (unsigned long) *buflen);
244    log_stacktrace();
245    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
246  }
247
248  memcpy(*buf, &byte, sizeof(char));
249  (*buf) += sizeof(char);
250  (*buflen) -= sizeof(char);
251}
252
253void sftp_msg_write_bool(char **buf, uint32_t *buflen, char bool) {
254  sftp_msg_write_byte(buf, buflen, bool == 0 ? 0 : 1);
255}
256
257void sftp_msg_write_data(char **buf, uint32_t *buflen, const char *data,
258   size_t datalen, int write_len) {
259
260  if (write_len)
261    sftp_msg_write_int(buf, buflen, datalen);
262
263  if (*buflen < datalen) {
264    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
265      "message format error: unable to write %lu bytes of raw data "
266      "(buflen = %lu)", (unsigned long) datalen, (unsigned long) *buflen);
267    log_stacktrace();
268    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
269  }
270
271  if (datalen > 0) {
272    memcpy(*buf, data, datalen);
273    (*buf) += datalen;
274    (*buflen) -= datalen;
275  }
276}
277
278void sftp_msg_write_int(char **buf, uint32_t *buflen, uint32_t val) {
279  if (*buflen < sizeof(uint32_t)) {
280    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
281      "message format error: unable to write int (buflen = %lu)",
282      (unsigned long) *buflen);
283    log_stacktrace();
284    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
285  }
286
287  val = htonl(val);
288  memcpy(*buf, &val, sizeof(uint32_t));
289  (*buf) += sizeof(uint32_t);
290  (*buflen) -= sizeof(uint32_t);
291}
292
293void sftp_msg_write_mpint(char **buf, uint32_t *buflen,
294    const BIGNUM *mpint) {
295  unsigned char *data = NULL;
296  size_t datalen = 0;
297  int res = 0;
298
299  if (BN_is_zero(mpint)) {
300    sftp_msg_write_int(buf, buflen, 0);
301    return;
302  }
303
304  if (mpint->neg) {
305    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
306      "message format error: unable to write mpint (negative numbers not "
307      "supported)");
308    log_stacktrace();
309    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
310  }
311
312  datalen = BN_num_bytes(mpint) + 1;
313
314  if (*buflen < datalen) {
315    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
316      "message format error: unable to write %lu bytes of mpint (buflen = %lu)",
317      (unsigned long) datalen, (unsigned long) *buflen);
318    log_stacktrace();
319    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
320  }
321
322  data = malloc(datalen);
323  if (data == NULL) {
324    pr_log_pri(PR_LOG_CRIT, MOD_SFTP_VERSION ": Out of memory!");
325    _exit(1);
326  }
327
328  data[0] = 0;
329
330  res = BN_bn2bin(mpint, data + 1);
331  if (res < 0 ||
332      res != (datalen - 1)) {
333    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
334      "message format error: BN_bn2bin() failed: expected %lu bytes, got %d",
335      (unsigned long) (datalen - 1), res);
336    pr_memscrub(data, datalen);
337    free(data);
338
339    SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
340  }
341
342  if (data[1] & 0x80) {
343    sftp_msg_write_data(buf, buflen, (char *) data, datalen, TRUE);
344
345  } else {
346    sftp_msg_write_data(buf, buflen, (char *) data + 1, datalen - 1, TRUE);
347  }
348
349  pr_memscrub(data, datalen);
350  free(data);
351}
352
353void sftp_msg_write_string(char **buf, uint32_t *buflen, const char *str) {
354  uint32_t len = 0;
355
356  len = strlen(str);
357  sftp_msg_write_data(buf, buflen, str, len, TRUE);
358}
Note: See TracBrowser for help on using the repository browser.