1 |
// |
2 |
// buffer.c |
3 |
// |
4 |
|
5 |
#include <winsock2.h> |
6 |
#include <malloc.h> |
7 |
#include "buffer.h" |
8 |
#include "ttxssh.h" |
9 |
#include "util.h" |
10 |
#include <openssl/bn.h> |
11 |
#include <zlib.h> |
12 |
|
13 |
void buffer_clear(buffer_t *buf) |
14 |
{ |
15 |
buf->offset = 0; |
16 |
buf->len = 0; |
17 |
} |
18 |
|
19 |
buffer_t *buffer_init(void) |
20 |
{ |
21 |
void *ptr; |
22 |
buffer_t *buf; |
23 |
int size = 4096; |
24 |
|
25 |
buf = malloc(sizeof(buffer_t)); |
26 |
ptr = malloc(size); |
27 |
if (buf && ptr) { |
28 |
memset(buf, 0, sizeof(buffer_t)); |
29 |
memset(ptr, 0, size); |
30 |
buf->buf = ptr; |
31 |
buf->maxlen = size; |
32 |
buf->len = 0; |
33 |
buf->offset = 0; |
34 |
|
35 |
} else { |
36 |
ptr = NULL; *(char *)ptr = 0; |
37 |
} |
38 |
|
39 |
return (buf); |
40 |
} |
41 |
|
42 |
void buffer_free(buffer_t * buf) |
43 |
{ |
44 |
if (buf != NULL) { |
45 |
// セキュリティ対策 (2006.8.3 yutaka) |
46 |
int len = buffer_len(buf); |
47 |
memset(buf->buf, 'x', len); |
48 |
free(buf->buf); |
49 |
free(buf); |
50 |
} |
51 |
} |
52 |
|
53 |
int buffer_append(buffer_t * buf, char *ptr, int size) |
54 |
{ |
55 |
int n; |
56 |
int ret = -1; |
57 |
int newlen; |
58 |
|
59 |
for (;;) { |
60 |
n = buf->offset + size; |
61 |
if (n < buf->maxlen) { |
62 |
memcpy(buf->buf + buf->offset, ptr, size); |
63 |
buf->offset += size; |
64 |
buf->len = buf->offset; |
65 |
ret = 0; |
66 |
break; |
67 |
|
68 |
} else { |
69 |
// バッファが足りないので補充する。(2005.7.2 yutaka) |
70 |
newlen = buf->maxlen + size + 32*1024; |
71 |
if (newlen > 0xa00000) { // 1MB over is not supported |
72 |
goto panic; |
73 |
} |
74 |
buf->buf = realloc(buf->buf, newlen); |
75 |
if (buf->buf == NULL) |
76 |
goto panic; |
77 |
buf->maxlen = newlen; |
78 |
} |
79 |
} |
80 |
|
81 |
return (ret); |
82 |
|
83 |
panic: |
84 |
{ |
85 |
char *p = NULL; |
86 |
*p = 0; // application fault |
87 |
} |
88 |
|
89 |
return (ret); |
90 |
} |
91 |
|
92 |
int buffer_append_length(buffer_t * msg, char *ptr, int size) |
93 |
{ |
94 |
char buf[4]; |
95 |
int val; |
96 |
int ret = -1; |
97 |
|
98 |
val = htonl(size); |
99 |
memcpy(buf, &val, sizeof(val)); |
100 |
ret = buffer_append(msg, buf, sizeof(buf)); |
101 |
if (ptr != NULL) { |
102 |
ret = buffer_append(msg, ptr, size); |
103 |
} |
104 |
|
105 |
return (ret); |
106 |
} |
107 |
|
108 |
void buffer_put_raw(buffer_t *msg, char *ptr, int size) |
109 |
{ |
110 |
int ret = -1; |
111 |
|
112 |
ret = buffer_append(msg, ptr, size); |
113 |
} |
114 |
|
115 |
// getting string buffer. |
116 |
// NOTE: You should free the return pointer if it's unused. |
117 |
// (2005.6.26 yutaka) |
118 |
char *buffer_get_string(char **data_ptr, int *buflen_ptr) |
119 |
{ |
120 |
char *data = *data_ptr; |
121 |
char *ptr; |
122 |
int buflen; |
123 |
|
124 |
buflen = get_uint32_MSBfirst(data); |
125 |
data += 4; |
126 |
if (buflen <= 0) |
127 |
return NULL; |
128 |
|
129 |
ptr = malloc(buflen + 1); |
130 |
if (ptr == NULL) { |
131 |
if (buflen_ptr != NULL) |
132 |
*buflen_ptr = 0; |
133 |
return NULL; |
134 |
} |
135 |
memcpy(ptr, data, buflen); |
136 |
ptr[buflen] = '\0'; // null-terminate |
137 |
data += buflen; |
138 |
|
139 |
*data_ptr = data; |
140 |
if (buflen_ptr != NULL) |
141 |
*buflen_ptr = buflen; |
142 |
|
143 |
return(ptr); |
144 |
} |
145 |
|
146 |
void buffer_put_string(buffer_t *msg, char *ptr, int size) |
147 |
{ |
148 |
char buf[4]; |
149 |
int val; |
150 |
int ret = -1; |
151 |
|
152 |
// 「サイズ+文字列」で書き込む。サイズは4byteのbig-endian。 |
153 |
val = htonl(size); |
154 |
memcpy(buf, &val, sizeof(val)); |
155 |
ret = buffer_append(msg, buf, sizeof(buf)); |
156 |
if (ptr != NULL) { |
157 |
ret = buffer_append(msg, ptr, size); |
158 |
} |
159 |
} |
160 |
|
161 |
void buffer_put_char(buffer_t *msg, int value) |
162 |
{ |
163 |
char ch = value; |
164 |
|
165 |
buffer_append(msg, &ch, 1); |
166 |
} |
167 |
|
168 |
void buffer_put_padding(buffer_t *msg, int size) |
169 |
{ |
170 |
char ch = ' '; |
171 |
int i; |
172 |
|
173 |
for (i = 0 ; i < size ; i++) { |
174 |
buffer_append(msg, &ch, 1); |
175 |
} |
176 |
} |
177 |
|
178 |
void buffer_put_int(buffer_t *msg, int value) |
179 |
{ |
180 |
char buf[4]; |
181 |
|
182 |
set_uint32_MSBfirst(buf, value); |
183 |
buffer_append(msg, buf, sizeof(buf)); |
184 |
} |
185 |
|
186 |
int buffer_len(buffer_t *msg) |
187 |
{ |
188 |
return (msg->len); |
189 |
} |
190 |
|
191 |
char *buffer_ptr(buffer_t *msg) |
192 |
{ |
193 |
return (msg->buf); |
194 |
} |
195 |
|
196 |
char *buffer_tail_ptr(buffer_t *msg) |
197 |
{ |
198 |
return (char *)(msg->buf + msg->offset); |
199 |
} |
200 |
|
201 |
int buffer_overflow_verify(buffer_t *msg, int len) |
202 |
{ |
203 |
if (msg->offset + len > msg->maxlen) { |
204 |
return -1; // error |
205 |
} |
206 |
return 0; // no problem |
207 |
} |
208 |
|
209 |
// for SSH1 |
210 |
void buffer_put_bignum(buffer_t *buffer, BIGNUM *value) |
211 |
{ |
212 |
unsigned int bits, bin_size; |
213 |
unsigned char *buf; |
214 |
int oi; |
215 |
char msg[2]; |
216 |
|
217 |
bits = BN_num_bits(value); |
218 |
bin_size = (bits + 7) / 8; |
219 |
buf = malloc(bin_size); |
220 |
if (buf == NULL) { |
221 |
*buf = 0; |
222 |
goto error; |
223 |
} |
224 |
|
225 |
buf[0] = '\0'; |
226 |
/* Get the value of in binary */ |
227 |
oi = BN_bn2bin(value, buf); |
228 |
if (oi != bin_size) { |
229 |
goto error; |
230 |
} |
231 |
|
232 |
/* Store the number of bits in the buffer in two bytes, msb first. */ |
233 |
set_ushort16_MSBfirst(msg, bits); |
234 |
buffer_append(buffer, msg, 2); |
235 |
|
236 |
/* Store the binary data. */ |
237 |
buffer_append(buffer, (char *)buf, oi); |
238 |
|
239 |
error: |
240 |
free(buf); |
241 |
} |
242 |
|
243 |
// for SSH2 |
244 |
void buffer_put_bignum2(buffer_t *msg, BIGNUM *value) |
245 |
{ |
246 |
unsigned int bytes; |
247 |
unsigned char *buf; |
248 |
int oi; |
249 |
unsigned int hasnohigh = 0; |
250 |
|
251 |
bytes = BN_num_bytes(value) + 1; /* extra padding byte */ |
252 |
buf = malloc(bytes); |
253 |
if (buf == NULL) { |
254 |
*buf = 0; |
255 |
goto error; |
256 |
} |
257 |
|
258 |
buf[0] = '\0'; |
259 |
/* Get the value of in binary */ |
260 |
oi = BN_bn2bin(value, buf+1); |
261 |
hasnohigh = (buf[1] & 0x80) ? 0 : 1; |
262 |
buffer_put_string(msg, buf+hasnohigh, bytes-hasnohigh); |
263 |
//memset(buf, 0, bytes); |
264 |
|
265 |
error: |
266 |
free(buf); |
267 |
} |
268 |
|
269 |
void buffer_get_bignum2(char **data, BIGNUM *value) |
270 |
{ |
271 |
char *buf = *data; |
272 |
int len; |
273 |
|
274 |
len = get_uint32_MSBfirst(buf); |
275 |
buf += 4; |
276 |
BN_bin2bn(buf, len, value); |
277 |
buf += len; |
278 |
|
279 |
*data = buf; |
280 |
} |
281 |
|
282 |
void buffer_dump(FILE *fp, buffer_t *buf) |
283 |
{ |
284 |
int i; |
285 |
char *ch = buffer_ptr(buf); |
286 |
|
287 |
for (i = 0 ; i < buffer_len(buf) ; i++) { |
288 |
fprintf(fp, "%02x", ch[i] & 0xff); |
289 |
if (i % 16 == 15) |
290 |
fprintf(fp, "\n"); |
291 |
else if (i % 2 == 1) |
292 |
fprintf(fp, " "); |
293 |
} |
294 |
fprintf(fp, "\n"); |
295 |
} |
296 |
|
297 |
// バッファのオフセットを進める。 |
298 |
void buffer_consume(buffer_t *buf, int shift_byte) |
299 |
{ |
300 |
int n; |
301 |
|
302 |
n = buf->offset + shift_byte; |
303 |
if (n < buf->maxlen) { |
304 |
buf->offset += shift_byte; |
305 |
} else { |
306 |
// TODO: fatal error |
307 |
} |
308 |
} |
309 |
|
310 |
// パケットの圧縮 |
311 |
int buffer_compress(z_stream *zstream, char *payload, int len, buffer_t *compbuf) |
312 |
{ |
313 |
unsigned char buf[4096]; |
314 |
int status; |
315 |
|
316 |
// input buffer |
317 |
zstream->next_in = payload; |
318 |
zstream->avail_in = len; |
319 |
|
320 |
do { |
321 |
// output buffer |
322 |
zstream->next_out = buf; |
323 |
zstream->avail_out = sizeof(buf); |
324 |
|
325 |
// バッファを圧縮する。圧縮すると、逆にサイズが大きくなることも考慮すること。 |
326 |
status = deflate(zstream, Z_PARTIAL_FLUSH); |
327 |
if (status == Z_OK) { |
328 |
buffer_append(compbuf, buf, sizeof(buf) - zstream->avail_out); |
329 |
} else { |
330 |
return -1; // error |
331 |
} |
332 |
} while (zstream->avail_out == 0); |
333 |
|
334 |
return 0; // success |
335 |
} |
336 |
|
337 |
// パケットの展開 |
338 |
int buffer_decompress(z_stream *zstream, char *payload, int len, buffer_t *compbuf) |
339 |
{ |
340 |
unsigned char buf[4096]; |
341 |
int status; |
342 |
|
343 |
// input buffer |
344 |
zstream->next_in = payload; |
345 |
zstream->avail_in = len; |
346 |
|
347 |
do { |
348 |
// output buffer |
349 |
zstream->next_out = buf; |
350 |
zstream->avail_out = sizeof(buf); |
351 |
|
352 |
// バッファを展開する。 |
353 |
status = inflate(zstream, Z_PARTIAL_FLUSH); |
354 |
if (status == Z_OK) { |
355 |
buffer_append(compbuf, buf, sizeof(buf) - zstream->avail_out); |
356 |
|
357 |
} else if (status == Z_OK) { |
358 |
break; |
359 |
|
360 |
} else { |
361 |
return -1; // error |
362 |
} |
363 |
} while (zstream->avail_out == 0); |
364 |
|
365 |
return 0; // success |
366 |
} |