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 |
// getting string buffer. |
109 |
// NOTE: You should free the return pointer if it's unused. |
110 |
// (2005.6.26 yutaka) |
111 |
char *buffer_get_string(char **data_ptr, int *buflen_ptr) |
112 |
{ |
113 |
char *data = *data_ptr; |
114 |
char *ptr; |
115 |
int buflen; |
116 |
|
117 |
buflen = get_uint32_MSBfirst(data); |
118 |
data += 4; |
119 |
if (buflen <= 0) |
120 |
return NULL; |
121 |
|
122 |
ptr = malloc(buflen + 1); |
123 |
if (ptr == NULL) { |
124 |
if (buflen_ptr != NULL) |
125 |
*buflen_ptr = 0; |
126 |
return NULL; |
127 |
} |
128 |
memcpy(ptr, data, buflen); |
129 |
ptr[buflen] = '\0'; // null-terminate |
130 |
data += buflen; |
131 |
|
132 |
*data_ptr = data; |
133 |
if (buflen_ptr != NULL) |
134 |
*buflen_ptr = buflen; |
135 |
|
136 |
return(ptr); |
137 |
} |
138 |
|
139 |
void buffer_put_string(buffer_t *msg, char *ptr, int size) |
140 |
{ |
141 |
char buf[4]; |
142 |
int val; |
143 |
int ret = -1; |
144 |
|
145 |
// 「サイズ+文字列」で書き込む。サイズは4byteのbig-endian。 |
146 |
val = htonl(size); |
147 |
memcpy(buf, &val, sizeof(val)); |
148 |
ret = buffer_append(msg, buf, sizeof(buf)); |
149 |
if (ptr != NULL) { |
150 |
ret = buffer_append(msg, ptr, size); |
151 |
} |
152 |
} |
153 |
|
154 |
void buffer_put_char(buffer_t *msg, int value) |
155 |
{ |
156 |
char ch = value; |
157 |
|
158 |
buffer_append(msg, &ch, 1); |
159 |
} |
160 |
|
161 |
void buffer_put_padding(buffer_t *msg, int size) |
162 |
{ |
163 |
char ch = ' '; |
164 |
int i; |
165 |
|
166 |
for (i = 0 ; i < size ; i++) { |
167 |
buffer_append(msg, &ch, 1); |
168 |
} |
169 |
} |
170 |
|
171 |
void buffer_put_int(buffer_t *msg, int value) |
172 |
{ |
173 |
char buf[4]; |
174 |
|
175 |
set_uint32_MSBfirst(buf, value); |
176 |
buffer_append(msg, buf, sizeof(buf)); |
177 |
} |
178 |
|
179 |
int buffer_len(buffer_t *msg) |
180 |
{ |
181 |
return (msg->len); |
182 |
} |
183 |
|
184 |
char *buffer_ptr(buffer_t *msg) |
185 |
{ |
186 |
return (msg->buf); |
187 |
} |
188 |
|
189 |
char *buffer_tail_ptr(buffer_t *msg) |
190 |
{ |
191 |
return (char *)(msg->buf + msg->offset); |
192 |
} |
193 |
|
194 |
int buffer_overflow_verify(buffer_t *msg, int len) |
195 |
{ |
196 |
if (msg->offset + len > msg->maxlen) { |
197 |
return -1; // error |
198 |
} |
199 |
return 0; // no problem |
200 |
} |
201 |
|
202 |
// for SSH1 |
203 |
void buffer_put_bignum(buffer_t *buffer, BIGNUM *value) |
204 |
{ |
205 |
unsigned int bits, bin_size; |
206 |
unsigned char *buf; |
207 |
int oi; |
208 |
char msg[2]; |
209 |
|
210 |
bits = BN_num_bits(value); |
211 |
bin_size = (bits + 7) / 8; |
212 |
buf = malloc(bin_size); |
213 |
if (buf == NULL) { |
214 |
*buf = 0; |
215 |
goto error; |
216 |
} |
217 |
|
218 |
buf[0] = '\0'; |
219 |
/* Get the value of in binary */ |
220 |
oi = BN_bn2bin(value, buf); |
221 |
if (oi != bin_size) { |
222 |
goto error; |
223 |
} |
224 |
|
225 |
/* Store the number of bits in the buffer in two bytes, msb first. */ |
226 |
set_ushort16_MSBfirst(msg, bits); |
227 |
buffer_append(buffer, msg, 2); |
228 |
|
229 |
/* Store the binary data. */ |
230 |
buffer_append(buffer, (char *)buf, oi); |
231 |
|
232 |
error: |
233 |
free(buf); |
234 |
} |
235 |
|
236 |
// for SSH2 |
237 |
void buffer_put_bignum2(buffer_t *msg, BIGNUM *value) |
238 |
{ |
239 |
unsigned int bytes; |
240 |
unsigned char *buf; |
241 |
int oi; |
242 |
unsigned int hasnohigh = 0; |
243 |
|
244 |
bytes = BN_num_bytes(value) + 1; /* extra padding byte */ |
245 |
buf = malloc(bytes); |
246 |
if (buf == NULL) { |
247 |
*buf = 0; |
248 |
goto error; |
249 |
} |
250 |
|
251 |
buf[0] = '\0'; |
252 |
/* Get the value of in binary */ |
253 |
oi = BN_bn2bin(value, buf+1); |
254 |
hasnohigh = (buf[1] & 0x80) ? 0 : 1; |
255 |
buffer_put_string(msg, buf+hasnohigh, bytes-hasnohigh); |
256 |
//memset(buf, 0, bytes); |
257 |
|
258 |
error: |
259 |
free(buf); |
260 |
} |
261 |
|
262 |
void buffer_get_bignum2(char **data, BIGNUM *value) |
263 |
{ |
264 |
char *buf = *data; |
265 |
int len; |
266 |
|
267 |
len = get_uint32_MSBfirst(buf); |
268 |
buf += 4; |
269 |
BN_bin2bn(buf, len, value); |
270 |
buf += len; |
271 |
|
272 |
*data = buf; |
273 |
} |
274 |
|
275 |
void buffer_dump(FILE *fp, buffer_t *buf) |
276 |
{ |
277 |
int i; |
278 |
char *ch = buffer_ptr(buf); |
279 |
|
280 |
for (i = 0 ; i < buffer_len(buf) ; i++) { |
281 |
fprintf(fp, "%02x", ch[i] & 0xff); |
282 |
if (i % 16 == 15) |
283 |
fprintf(fp, "\n"); |
284 |
else if (i % 2 == 1) |
285 |
fprintf(fp, " "); |
286 |
} |
287 |
fprintf(fp, "\n"); |
288 |
} |
289 |
|
290 |
// バッファのオフセットを進める。 |
291 |
void buffer_consume(buffer_t *buf, int shift_byte) |
292 |
{ |
293 |
int n; |
294 |
|
295 |
n = buf->offset + shift_byte; |
296 |
if (n < buf->maxlen) { |
297 |
buf->offset += shift_byte; |
298 |
} else { |
299 |
// TODO: fatal error |
300 |
} |
301 |
} |
302 |
|
303 |
// パケットの圧縮 |
304 |
int buffer_compress(z_stream *zstream, char *payload, int len, buffer_t *compbuf) |
305 |
{ |
306 |
unsigned char buf[4096]; |
307 |
int status; |
308 |
|
309 |
// input buffer |
310 |
zstream->next_in = payload; |
311 |
zstream->avail_in = len; |
312 |
|
313 |
do { |
314 |
// output buffer |
315 |
zstream->next_out = buf; |
316 |
zstream->avail_out = sizeof(buf); |
317 |
|
318 |
// バッファを圧縮する。圧縮すると、逆にサイズが大きくなることも考慮すること。 |
319 |
status = deflate(zstream, Z_PARTIAL_FLUSH); |
320 |
if (status == Z_OK) { |
321 |
buffer_append(compbuf, buf, sizeof(buf) - zstream->avail_out); |
322 |
} else { |
323 |
return -1; // error |
324 |
} |
325 |
} while (zstream->avail_out == 0); |
326 |
|
327 |
return 0; // success |
328 |
} |
329 |
|
330 |
// パケットの展開 |
331 |
int buffer_decompress(z_stream *zstream, char *payload, int len, buffer_t *compbuf) |
332 |
{ |
333 |
unsigned char buf[4096]; |
334 |
int status; |
335 |
|
336 |
// input buffer |
337 |
zstream->next_in = payload; |
338 |
zstream->avail_in = len; |
339 |
|
340 |
do { |
341 |
// output buffer |
342 |
zstream->next_out = buf; |
343 |
zstream->avail_out = sizeof(buf); |
344 |
|
345 |
// バッファを展開する。 |
346 |
status = inflate(zstream, Z_PARTIAL_FLUSH); |
347 |
if (status == Z_OK) { |
348 |
buffer_append(compbuf, buf, sizeof(buf) - zstream->avail_out); |
349 |
|
350 |
} else if (status == Z_OK) { |
351 |
break; |
352 |
|
353 |
} else { |
354 |
return -1; // error |
355 |
} |
356 |
} while (zstream->avail_out == 0); |
357 |
|
358 |
return 0; // success |
359 |
} |